tests
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -577,6 +577,498 @@ public readonly partial record struct {typeName} : IMensuraUnit<{typeName}>, IEq
|
|||||||
public static {typeName}[] operator /({typeName}? T1, UInt128[] T2) => T1.ProtectedU().Div(T2.ToDouble());
|
public static {typeName}[] operator /({typeName}? T1, UInt128[] T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
public static {typeName}?[] operator /({typeName}? T1, UInt128?[] T2) => T1.ProtectedU().Div(T2.ToDouble());
|
public static {typeName}?[] operator /({typeName}? T1, UInt128?[] T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static List<{typeName}> operator +(List<{typeName}> T1, {typeName} T2) => T1.Plus(T2._Value);
|
||||||
|
public static List<{typeName}?> operator +(List<{typeName}?> T1, {typeName} T2) => T1.Plus(T2._Value);
|
||||||
|
public static List<{typeName}> operator +({typeName} T1, List<{typeName}> T2) => T1._Value.Plus(T2);
|
||||||
|
public static List<{typeName}?> operator +({typeName} T1, List<{typeName}?> T2) => T1._Value.Plus(T2);
|
||||||
|
public static List<{typeName}> operator +(List<{typeName}> T1, {typeName}? T2) => T1.Plus(T2.Protected());
|
||||||
|
public static List<{typeName}?> operator +(List<{typeName}?> T1, {typeName}? T2) => T1.Plus(T2.Protected());
|
||||||
|
public static List<{typeName}> operator +({typeName}? T1, List<{typeName}> T2) => T1.Protected().Plus(T2);
|
||||||
|
public static List<{typeName}?> operator +({typeName}? T1, List<{typeName}?> T2) => T1.Protected().Plus(T2);
|
||||||
|
|
||||||
|
public static List<{typeName}> operator -(List<{typeName}> T1, {typeName} T2) => T1.Minus(T2._Value);
|
||||||
|
public static List<{typeName}?> operator -(List<{typeName}?> T1, {typeName} T2) => T1.Minus(T2._Value);
|
||||||
|
public static List<{typeName}> operator -({typeName} T1, List<{typeName}> T2) => T1._Value.Minus(T2);
|
||||||
|
public static List<{typeName}?> operator -({typeName} T1, List<{typeName}?> T2) => T1._Value.Minus(T2);
|
||||||
|
public static List<{typeName}> operator -(List<{typeName}> T1, {typeName}? T2) => T1.Minus(T2.Protected());
|
||||||
|
public static List<{typeName}?> operator -(List<{typeName}?> T1, {typeName}? T2) => T1.Minus(T2.Protected());
|
||||||
|
public static List<{typeName}> operator -({typeName}? T1, List<{typeName}> T2) => T1.Protected().Minus(T2);
|
||||||
|
public static List<{typeName}?> operator -({typeName}? T1, List<{typeName}?> T2) => T1.Protected().Minus(T2);
|
||||||
|
|
||||||
|
public static List<double> operator /({typeName} T1, List<{typeName}> T2) => T1.Div(T2);
|
||||||
|
public static List<double?> operator /({typeName} T1, List<{typeName}?> T2) => T1.Div(T2);
|
||||||
|
public static List<double> operator /(List<{typeName}> T1, {typeName} T2) => T1.Div(T2);
|
||||||
|
public static List<double?> operator /(List<{typeName}?> T1, {typeName} T2) => T1.Div(T2);
|
||||||
|
public static List<double> operator /({typeName}? T1, List<{typeName}> T2) => T1.ProtectedU().Div(T2);
|
||||||
|
public static List<double?> operator /({typeName}? T1, List<{typeName}?> T2) => T1.ProtectedU().Div(T2);
|
||||||
|
public static List<double> operator /(List<{typeName}> T1, {typeName}? T2) => T1.Div(T2.ProtectedU());
|
||||||
|
public static List<double?> operator /(List<{typeName}?> T1, {typeName}? T2) => T1.Div(T2.ProtectedU());
|
||||||
|
|
||||||
|
|
||||||
|
// double
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<double> T2) => T1.Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<double?> T2) => T1.Mul(T2);
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<double> T2) => T1.ProtectedU().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<double?> T2) => T1.ProtectedU().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<double> T1, {typeName} T2) => T1.Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<double?> T1, {typeName} T2) => T1.Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<double> T1, {typeName}? T2) => T1.Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<double?> T1, {typeName}? T2) => T1.Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<double> T2) => T1.Div(T2);
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<double?> T2) => T1.Div(T2);
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<double> T2) => T1.ProtectedU().Div(T2);
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<double?> T2) => T1.ProtectedU().Div(T2);
|
||||||
|
|
||||||
|
// sbyte
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<sbyte> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<sbyte?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<sbyte> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<sbyte?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<sbyte> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<sbyte?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<sbyte> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<sbyte?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<sbyte> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<sbyte?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<sbyte> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<sbyte?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// short
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<short> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<short?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<short> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<short?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<short> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<short?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<short> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<short?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<short> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<short?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<short> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<short?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// int
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<int> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<int?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<int> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<int?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<int> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<int?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<int> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<int?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<int> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<int?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<int> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<int?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// long
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<long> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<long?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<long> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<long?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<long> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<long?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<long> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<long?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<long> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<long?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<long> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<long?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// byte
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<byte> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<byte?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<byte> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<byte?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<byte> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<byte?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<byte> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<byte?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<byte> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<byte?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<byte> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<byte?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// ushort
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<ushort> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<ushort?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<ushort> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<ushort?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<ushort> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<ushort?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<ushort> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<ushort?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<ushort> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<ushort?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<ushort> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<ushort?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// uint
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<uint> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<uint?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<uint> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<uint?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<uint> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<uint?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<uint> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<uint?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<uint> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<uint?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<uint> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<uint?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// ulong
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<ulong> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<ulong?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<ulong> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<ulong?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<ulong> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<ulong?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<ulong> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<ulong?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<ulong> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<ulong?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<ulong> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<ulong?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// nint
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<nint> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<nint?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<nint> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<nint?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<nint> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<nint?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<nint> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<nint?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<nint> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<nint?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<nint> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<nint?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// nuint
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<nuint> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<nuint?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<nuint> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<nuint?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<nuint> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<nuint?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<nuint> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<nuint?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<nuint> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<nuint?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<nuint> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<nuint?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// float
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<float> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<float?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<float> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<float?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<float> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<float?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<float> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<float?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<float> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<float?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<float> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<float?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// decimal
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<decimal> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<decimal?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<decimal> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<decimal?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<decimal> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<decimal?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<decimal> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<decimal?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<decimal> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<decimal?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<decimal> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<decimal?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
#if NET7_0_OR_GREATER
|
||||||
|
// Int128
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<Int128> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<Int128?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<Int128> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<Int128?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<Int128> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<Int128?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<Int128> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<Int128?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<Int128> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<Int128?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<Int128> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<Int128?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// UInt128
|
||||||
|
public static List<{typeName}> operator *({typeName} T1, List<UInt128> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName} T1, List<UInt128?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *({typeName}? T1, List<UInt128> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator *({typeName}? T1, List<UInt128?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator *(List<UInt128> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}?> operator *(List<UInt128?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static List<{typeName}> operator *(List<UInt128> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}?> operator *(List<UInt128?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static List<{typeName}> operator /({typeName} T1, List<UInt128> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName} T1, List<UInt128?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}> operator /({typeName}? T1, List<UInt128> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static List<{typeName}?> operator /({typeName}? T1, List<UInt128?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static IEnumerable<{typeName}> operator +(IEnumerable<{typeName}> T1, {typeName} T2) => T1.Plus(T2._Value);
|
||||||
|
public static IEnumerable<{typeName}?> operator +(IEnumerable<{typeName}?> T1, {typeName} T2) => T1.Plus(T2._Value);
|
||||||
|
public static IEnumerable<{typeName}> operator +({typeName} T1, IEnumerable<{typeName}> T2) => T1._Value.Plus(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator +({typeName} T1, IEnumerable<{typeName}?> T2) => T1._Value.Plus(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator +(IEnumerable<{typeName}> T1, {typeName}? T2) => T1.Plus(T2.Protected());
|
||||||
|
public static IEnumerable<{typeName}?> operator +(IEnumerable<{typeName}?> T1, {typeName}? T2) => T1.Plus(T2.Protected());
|
||||||
|
public static IEnumerable<{typeName}> operator +({typeName}? T1, IEnumerable<{typeName}> T2) => T1.Protected().Plus(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator +({typeName}? T1, IEnumerable<{typeName}?> T2) => T1.Protected().Plus(T2);
|
||||||
|
|
||||||
|
public static IEnumerable<{typeName}> operator -(IEnumerable<{typeName}> T1, {typeName} T2) => T1.Minus(T2._Value);
|
||||||
|
public static IEnumerable<{typeName}?> operator -(IEnumerable<{typeName}?> T1, {typeName} T2) => T1.Minus(T2._Value);
|
||||||
|
public static IEnumerable<{typeName}> operator -({typeName} T1, IEnumerable<{typeName}> T2) => T1._Value.Minus(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator -({typeName} T1, IEnumerable<{typeName}?> T2) => T1._Value.Minus(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator -(IEnumerable<{typeName}> T1, {typeName}? T2) => T1.Minus(T2.Protected());
|
||||||
|
public static IEnumerable<{typeName}?> operator -(IEnumerable<{typeName}?> T1, {typeName}? T2) => T1.Minus(T2.Protected());
|
||||||
|
public static IEnumerable<{typeName}> operator -({typeName}? T1, IEnumerable<{typeName}> T2) => T1.Protected().Minus(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator -({typeName}? T1, IEnumerable<{typeName}?> T2) => T1.Protected().Minus(T2);
|
||||||
|
|
||||||
|
public static IEnumerable<double> operator /({typeName} T1, IEnumerable<{typeName}> T2) => T1.Div(T2);
|
||||||
|
public static IEnumerable<double?> operator /({typeName} T1, IEnumerable<{typeName}?> T2) => T1.Div(T2);
|
||||||
|
public static IEnumerable<double> operator /(IEnumerable<{typeName}> T1, {typeName} T2) => T1.Div(T2);
|
||||||
|
public static IEnumerable<double?> operator /(IEnumerable<{typeName}?> T1, {typeName} T2) => T1.Div(T2);
|
||||||
|
public static IEnumerable<double> operator /({typeName}? T1, IEnumerable<{typeName}> T2) => T1.ProtectedU().Div(T2);
|
||||||
|
public static IEnumerable<double?> operator /({typeName}? T1, IEnumerable<{typeName}?> T2) => T1.ProtectedU().Div(T2);
|
||||||
|
public static IEnumerable<double> operator /(IEnumerable<{typeName}> T1, {typeName}? T2) => T1.Div(T2.ProtectedU());
|
||||||
|
public static IEnumerable<double?> operator /(IEnumerable<{typeName}?> T1, {typeName}? T2) => T1.Div(T2.ProtectedU());
|
||||||
|
|
||||||
|
|
||||||
|
// double
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<double> T2) => T1.Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<double?> T2) => T1.Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<double> T2) => T1.ProtectedU().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<double?> T2) => T1.ProtectedU().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<double> T1, {typeName} T2) => T1.Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<double?> T1, {typeName} T2) => T1.Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<double> T1, {typeName}? T2) => T1.Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<double?> T1, {typeName}? T2) => T1.Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<double> T2) => T1.Div(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<double?> T2) => T1.Div(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<double> T2) => T1.ProtectedU().Div(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<double?> T2) => T1.ProtectedU().Div(T2);
|
||||||
|
|
||||||
|
// sbyte
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<sbyte> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<sbyte?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<sbyte> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<sbyte?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<sbyte> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<sbyte?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<sbyte> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<sbyte?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<sbyte> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<sbyte?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<sbyte> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<sbyte?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// short
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<short> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<short?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<short> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<short?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<short> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<short?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<short> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<short?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<short> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<short?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<short> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<short?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// int
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<int> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<int?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<int> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<int?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<int> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<int?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<int> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<int?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<int> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<int?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<int> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<int?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// long
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<long> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<long?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<long> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<long?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<long> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<long?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<long> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<long?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<long> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<long?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<long> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<long?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// byte
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<byte> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<byte?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<byte> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<byte?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<byte> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<byte?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<byte> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<byte?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<byte> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<byte?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<byte> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<byte?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// ushort
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<ushort> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<ushort?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<ushort> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<ushort?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<ushort> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<ushort?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<ushort> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<ushort?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<ushort> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<ushort?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<ushort> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<ushort?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// uint
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<uint> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<uint?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<uint> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<uint?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<uint> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<uint?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<uint> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<uint?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<uint> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<uint?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<uint> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<uint?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// ulong
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<ulong> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<ulong?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<ulong> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<ulong?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<ulong> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<ulong?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<ulong> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<ulong?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<ulong> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<ulong?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<ulong> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<ulong?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// nint
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<nint> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<nint?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<nint> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<nint?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<nint> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<nint?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<nint> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<nint?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<nint> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<nint?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<nint> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<nint?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// nuint
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<nuint> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<nuint?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<nuint> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<nuint?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<nuint> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<nuint?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<nuint> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<nuint?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<nuint> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<nuint?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<nuint> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<nuint?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// float
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<float> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<float?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<float> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<float?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<float> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<float?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<float> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<float?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<float> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<float?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<float> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<float?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// decimal
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<decimal> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<decimal?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<decimal> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<decimal?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<decimal> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<decimal?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<decimal> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<decimal?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<decimal> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<decimal?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<decimal> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<decimal?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
#if NET7_0_OR_GREATER
|
||||||
|
// Int128
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<Int128> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<Int128?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<Int128> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<Int128?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<Int128> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<Int128?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<Int128> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<Int128?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<Int128> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<Int128?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<Int128> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<Int128?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
|
||||||
|
// UInt128
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName} T1, IEnumerable<UInt128> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName} T1, IEnumerable<UInt128?> T2) => T1.Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *({typeName}? T1, IEnumerable<UInt128> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator *({typeName}? T1, IEnumerable<UInt128?> T2) => T1.ProtectedU().Mul(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<UInt128> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<UInt128?> T1, {typeName} T2) => T1.ToDouble().Mul(T2);
|
||||||
|
public static IEnumerable<{typeName}> operator *(IEnumerable<UInt128> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}?> operator *(IEnumerable<UInt128?> T1, {typeName}? T2) => T1.ToDouble().Mul(T2.ProtectedU());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName} T1, IEnumerable<UInt128> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName} T1, IEnumerable<UInt128?> T2) => T1.Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}> operator /({typeName}? T1, IEnumerable<UInt128> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
public static IEnumerable<{typeName}?> operator /({typeName}? T1, IEnumerable<UInt128?> T2) => T1.ProtectedU().Div(T2.ToDouble());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class {typeName}Extensions
|
public static class {typeName}Extensions
|
||||||
@@ -619,16 +1111,6 @@ public static class {typeName}Extensions
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeName}?> Div(
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeName}?> Div(
|
||||||
this double dividend, List<{typeName}?> units) => dividend.Div<{typeName}>(units);
|
this double dividend, List<{typeName}?> units) => dividend.Div<{typeName}>(units);
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Div(this ICollection<{typeName}> units,
|
|
||||||
double divisor, Span<{typeName}> destination) => units.Div<{typeName}>(divisor, destination);
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Div(this ICollection<{typeName}?> units,
|
|
||||||
double divisor, Span<{typeName}?> destination) => units.Div<{typeName}>(divisor, destination);
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Div(this double dividend,
|
|
||||||
ICollection<{typeName}> units, Span<{typeName}> destination) => dividend.Div<{typeName}>(units, destination);
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Div(this double dividend,
|
|
||||||
ICollection<{typeName}?> units, Span<{typeName}?> destination) => dividend.Div<{typeName}>(units, destination);
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static void Div(this IReadOnlyCollection<{typeName}> units,
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static void Div(this IReadOnlyCollection<{typeName}> units,
|
||||||
double divisor, Span<{typeName}> destination) => units.Div<{typeName}>(divisor, destination);
|
double divisor, Span<{typeName}> destination) => units.Div<{typeName}>(divisor, destination);
|
||||||
@@ -684,16 +1166,6 @@ public static class {typeName}Extensions
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeName}?> Mul(
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<{typeName}?> Mul(
|
||||||
this double multiplicator, List<{typeName}?> units) => units.Mul<{typeName}>(multiplicator);
|
this double multiplicator, List<{typeName}?> units) => units.Mul<{typeName}>(multiplicator);
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Mul(this ICollection<{typeName}> units,
|
|
||||||
double multiplicator, Span<{typeName}> destination) => units.Mul<{typeName}>(multiplicator, destination);
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Mul(this ICollection<{typeName}?> units,
|
|
||||||
double multiplicator, Span<{typeName}?> destination) => units.Mul<{typeName}>(multiplicator, destination);
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Mul(this double multiplicator,
|
|
||||||
ICollection<{typeName}> units, Span<{typeName}> destination) => units.Mul<{typeName}>(multiplicator, destination);
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Mul(this double multiplicator,
|
|
||||||
ICollection<{typeName}?> units, Span<{typeName}?> destination) => units.Mul<{typeName}>(multiplicator, destination);
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static void Mul(this IReadOnlyCollection<{typeName}> units,
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static void Mul(this IReadOnlyCollection<{typeName}> units,
|
||||||
double multiplicator, Span<{typeName}> destination) => units.Mul<{typeName}>(multiplicator, destination);
|
double multiplicator, Span<{typeName}> destination) => units.Mul<{typeName}>(multiplicator, destination);
|
||||||
@@ -734,12 +1206,6 @@ public static class {typeName}Extensions
|
|||||||
public static {typeName} Max(this List<{typeName}> list) => AggregateUnitExtensions.Max(list);
|
public static {typeName} Max(this List<{typeName}> list) => AggregateUnitExtensions.Max(list);
|
||||||
public static {typeName} Min(this List<{typeName}> list) => AggregateUnitExtensions.Min(list);
|
public static {typeName} Min(this List<{typeName}> list) => AggregateUnitExtensions.Min(list);
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
public static {typeName} Sum(this ICollection<{typeName}> collection) => AggregateUnitExtensions.Sum(collection);
|
|
||||||
public static {typeName} Avg(this ICollection<{typeName}> collection) => AggregateUnitExtensions.Avg(collection);
|
|
||||||
public static {typeName} Max(this ICollection<{typeName}> collection) => AggregateUnitExtensions.Max(collection);
|
|
||||||
public static {typeName} Min(this ICollection<{typeName}> collection) => AggregateUnitExtensions.Min(collection);
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
public static {typeName} Sum(this IReadOnlyCollection<{typeName}> collection) => AggregateUnitExtensions.Sum(collection);
|
public static {typeName} Sum(this IReadOnlyCollection<{typeName}> collection) => AggregateUnitExtensions.Sum(collection);
|
||||||
public static {typeName} Avg(this IReadOnlyCollection<{typeName}> collection) => AggregateUnitExtensions.Avg(collection);
|
public static {typeName} Avg(this IReadOnlyCollection<{typeName}> collection) => AggregateUnitExtensions.Avg(collection);
|
||||||
@@ -770,12 +1236,6 @@ public static class {typeName}Extensions
|
|||||||
public static {typeName} Max(this List<{typeName}?> list) => AggregateUnitExtensions.Max(list);
|
public static {typeName} Max(this List<{typeName}?> list) => AggregateUnitExtensions.Max(list);
|
||||||
public static {typeName} Min(this List<{typeName}?> list) => AggregateUnitExtensions.Min(list);
|
public static {typeName} Min(this List<{typeName}?> list) => AggregateUnitExtensions.Min(list);
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
public static {typeName} Sum(this ICollection<{typeName}?> collection) => AggregateUnitExtensions.Sum(collection);
|
|
||||||
public static {typeName} Avg(this ICollection<{typeName}?> collection) => AggregateUnitExtensions.Avg(collection);
|
|
||||||
public static {typeName} Max(this ICollection<{typeName}?> collection) => AggregateUnitExtensions.Max(collection);
|
|
||||||
public static {typeName} Min(this ICollection<{typeName}?> collection) => AggregateUnitExtensions.Min(collection);
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
public static {typeName} Sum(this IReadOnlyCollection<{typeName}?> collection) => AggregateUnitExtensions.Sum(collection);
|
public static {typeName} Sum(this IReadOnlyCollection<{typeName}?> collection) => AggregateUnitExtensions.Sum(collection);
|
||||||
public static {typeName} Avg(this IReadOnlyCollection<{typeName}?> collection) => AggregateUnitExtensions.Avg(collection);
|
public static {typeName} Avg(this IReadOnlyCollection<{typeName}?> collection) => AggregateUnitExtensions.Avg(collection);
|
||||||
|
|||||||
170
QWERTYkez.Mensura.Tests/AggregateUnitExtensions.cs
Normal file
170
QWERTYkez.Mensura.Tests/AggregateUnitExtensions.cs
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace QWERTYkez.Mensura.Tests;
|
||||||
|
|
||||||
|
public class AggregateUnitExtensions
|
||||||
|
{
|
||||||
|
// Вспомогательный метод для создания объекта Length.
|
||||||
|
// Если у вас используется фабричный метод (например, Length.FromMeters), замените код внутри.
|
||||||
|
private static Length CreateLength(double value) => value * Length._MilliMeter;
|
||||||
|
|
||||||
|
#region Инфраструктура Рефлексии (Invoker)
|
||||||
|
|
||||||
|
private delegate Length SpanDelegate(ReadOnlySpan<Length> units);
|
||||||
|
private delegate Length SpanNullableDelegate(ReadOnlySpan<Length?> units);
|
||||||
|
|
||||||
|
private static class Invoker
|
||||||
|
{
|
||||||
|
private static readonly Type ExtType;
|
||||||
|
|
||||||
|
static Invoker()
|
||||||
|
{
|
||||||
|
// Находим внутренний класс AggregateUnitExtensions в целевой сборке
|
||||||
|
ExtType = typeof(Length).Assembly.GetType("QWERTYkez.Mensura.Extensions.AggregateUnitExtensions")
|
||||||
|
?? throw new InvalidOperationException("Не удалось найти класс AggregateUnitExtensions через рефлексию.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Length InvokeSpan(string methodName, ReadOnlySpan<Length> data)
|
||||||
|
{
|
||||||
|
var method = FindMethod(methodName, typeof(ReadOnlySpan<>), isNullable: false);
|
||||||
|
var closedMethod = method.MakeGenericMethod(typeof(Length));
|
||||||
|
var del = closedMethod.CreateDelegate<SpanDelegate>();
|
||||||
|
return del(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Length InvokeSpanNullable(string methodName, ReadOnlySpan<Length?> data)
|
||||||
|
{
|
||||||
|
var method = FindMethod(methodName, typeof(ReadOnlySpan<>), isNullable: true);
|
||||||
|
var closedMethod = method.MakeGenericMethod(typeof(Length));
|
||||||
|
var del = closedMethod.CreateDelegate<SpanNullableDelegate>();
|
||||||
|
return del(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Length InvokeCollection(string methodName, Type genericContainer, object data, bool isNullable)
|
||||||
|
{
|
||||||
|
var method = FindMethod(methodName, genericContainer, isNullable);
|
||||||
|
var closedMethod = method.MakeGenericMethod(typeof(Length));
|
||||||
|
return (Length)closedMethod.Invoke(null, [data])!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodInfo FindMethod(string name, Type genericContainerType, bool isNullable)
|
||||||
|
{
|
||||||
|
var methods = ExtType.GetMethods(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)
|
||||||
|
.Where(m => m.Name == name);
|
||||||
|
|
||||||
|
foreach (var method in methods)
|
||||||
|
{
|
||||||
|
var parameters = method.GetParameters();
|
||||||
|
if (parameters.Length != 1) continue;
|
||||||
|
|
||||||
|
var paramType = parameters[0].ParameterType;
|
||||||
|
if (!paramType.IsGenericType) continue;
|
||||||
|
|
||||||
|
// Проверяем базовый контейнер (List<>, IEnumerable<>, ReadOnlySpan<>)
|
||||||
|
if (paramType.GetGenericTypeDefinition() != genericContainerType) continue;
|
||||||
|
|
||||||
|
// Проверяем внутренний аргумент типа на Nullable
|
||||||
|
var genericArgument = paramType.GetGenericArguments()[0];
|
||||||
|
bool currentIsNullable = genericArgument.IsGenericType &&
|
||||||
|
genericArgument.GetGenericTypeDefinition() == typeof(Nullable<>);
|
||||||
|
|
||||||
|
if (currentIsNullable == isNullable)
|
||||||
|
{
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new MethodAccessException($"Метод {name} для контейнера {genericContainerType.Name} (Nullable: {isNullable}) не найден.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Тесты для НЕ-выделяющих Nullable типов (Обычные структуры)
|
||||||
|
|
||||||
|
private readonly Length[] _standardData = [CreateLength(10), CreateLength(20), CreateLength(30)];
|
||||||
|
private readonly Length _expectedSum = CreateLength(60);
|
||||||
|
private readonly Length _expectedAvg = CreateLength(20);
|
||||||
|
private readonly Length _expectedMax = CreateLength(30);
|
||||||
|
private readonly Length _expectedMin = CreateLength(10);
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("Sum")]
|
||||||
|
[InlineData("Avg")]
|
||||||
|
[InlineData("Max")]
|
||||||
|
[InlineData("Min")]
|
||||||
|
public void StandardContainers_ShouldCalculateCorrectly(string operation)
|
||||||
|
{
|
||||||
|
// Набор ожидаемых значений
|
||||||
|
Length expected = operation switch
|
||||||
|
{
|
||||||
|
"Sum" => _expectedSum,
|
||||||
|
"Avg" => _expectedAvg,
|
||||||
|
"Max" => _expectedMax,
|
||||||
|
"Min" => _expectedMin,
|
||||||
|
_ => throw new ArgumentException(operation)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1. Тест ReadOnlySpan<T>
|
||||||
|
ReadOnlySpan<Length> span = _standardData;
|
||||||
|
Assert.Equal(expected, Invoker.InvokeSpan(operation, span));
|
||||||
|
|
||||||
|
// 2. Тест List<T>
|
||||||
|
var list = _standardData.ToList();
|
||||||
|
Assert.Equal(expected, Invoker.InvokeCollection(operation, typeof(List<>), list, isNullable: false));
|
||||||
|
|
||||||
|
// 3. Тест IReadOnlyCollection<T>
|
||||||
|
IReadOnlyCollection<Length> readOnlyCollection = _standardData;
|
||||||
|
Assert.Equal(expected, Invoker.InvokeCollection(operation, typeof(IReadOnlyCollection<>), readOnlyCollection, isNullable: false));
|
||||||
|
|
||||||
|
// 4. Тест IEnumerable<T>
|
||||||
|
IEnumerable<Length> enumerable = _standardData.Select(x => x);
|
||||||
|
Assert.Equal(expected, Invoker.InvokeCollection(operation, typeof(IEnumerable<>), enumerable, isNullable: false));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Тесты для Nullable типов (T?)
|
||||||
|
|
||||||
|
// Тестируем смесь значений с null-элементами
|
||||||
|
private readonly Length?[] _nullableData = [CreateLength(10), null, CreateLength(30)];
|
||||||
|
private readonly Length _expectedNullSum = CreateLength(40);
|
||||||
|
private readonly Length _expectedNullAvg = CreateLength(20); // 40 / 2 значения
|
||||||
|
private readonly Length _expectedNullMax = CreateLength(30);
|
||||||
|
private readonly Length _expectedNullMin = CreateLength(10);
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("Sum")]
|
||||||
|
[InlineData("Avg")]
|
||||||
|
[InlineData("Max")]
|
||||||
|
[InlineData("Min")]
|
||||||
|
public void NullableContainers_ShouldCalculateCorrectly(string operation)
|
||||||
|
{
|
||||||
|
Length expected = operation switch
|
||||||
|
{
|
||||||
|
"Sum" => _expectedNullSum,
|
||||||
|
"Avg" => _expectedNullAvg,
|
||||||
|
"Max" => _expectedNullMax,
|
||||||
|
"Min" => _expectedNullMin,
|
||||||
|
_ => throw new ArgumentException(operation)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1. Тест ReadOnlySpan<T?>
|
||||||
|
ReadOnlySpan<Length?> span = _nullableData;
|
||||||
|
Assert.Equal(expected, Invoker.InvokeSpanNullable(operation, span));
|
||||||
|
|
||||||
|
// 2. Тест List<T?>
|
||||||
|
var list = _nullableData.ToList();
|
||||||
|
Assert.Equal(expected, Invoker.InvokeCollection(operation, typeof(List<>), list, isNullable: true));
|
||||||
|
|
||||||
|
// 3. Тест IReadOnlyCollection<T?>
|
||||||
|
IReadOnlyCollection<Length?> readOnlyCollection = _nullableData;
|
||||||
|
Assert.Equal(expected, Invoker.InvokeCollection(operation, typeof(IReadOnlyCollection<>), readOnlyCollection, isNullable: true));
|
||||||
|
|
||||||
|
// 4. Тест IEnumerable<T?>
|
||||||
|
IEnumerable<Length?> enumerable = _nullableData.Select(x => x);
|
||||||
|
Assert.Equal(expected, Invoker.InvokeCollection(operation, typeof(IEnumerable<>), enumerable, isNullable: true));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
165
QWERTYkez.Mensura.Tests/CastExtensions.cs
Normal file
165
QWERTYkez.Mensura.Tests/CastExtensions.cs
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
namespace QWERTYkez.Mensura.Tests;
|
||||||
|
|
||||||
|
public class CastExtensions
|
||||||
|
{
|
||||||
|
private const double NormalValue1 = 42.42;
|
||||||
|
private const double NormalValue2 = 100.05;
|
||||||
|
|
||||||
|
#region 1. Слабое место: Побитовая идентичность и спец-значения (NaN/Inf)
|
||||||
|
// Так как используется Unsafe.As, нужно убедиться, что битовая сетка double
|
||||||
|
// не ломается при сохранении пограничных значений (NaN, Infinity).
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(NormalValue1)]
|
||||||
|
[InlineData(double.NaN)]
|
||||||
|
[InlineData(double.PositiveInfinity)]
|
||||||
|
[InlineData(double.NegativeInfinity)]
|
||||||
|
[InlineData(double.Epsilon)]
|
||||||
|
public void SingleConversion_Should_Preserve_Exact_BitPattern_For_Special_Doubles(double specialValue)
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
Length unit = specialValue.ToUnit<Length>();
|
||||||
|
double recovered = unit.ToDouble();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
// Используем BitConverter, чтобы проверить идентичность на уровне битов (особенно важно для NaN)
|
||||||
|
long originalBits = BitConverter.DoubleToInt64Bits(specialValue);
|
||||||
|
long recoveredBits = BitConverter.DoubleToInt64Bits(recovered);
|
||||||
|
|
||||||
|
Assert.Equal(originalBits, recoveredBits);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 2. Слабое место: Взрыв CLR при изменении емкости (EnsureCapacity)
|
||||||
|
// При ReCast списков подменяется MethodTable самого списка и его внутреннего массива.
|
||||||
|
// Если мы начнем добавлять элементы, список выделит новый массив через Array.CreateInstance.
|
||||||
|
// Если тип в MethodTable не совпадет с тем, что ожидает среда исполнения, GC или рантайм упадет.
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void List_ReCast_Should_Survive_Massive_Resize_And_GC_Collections()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var originalList = new List<Length> { (Length)NormalValue1, (Length)NormalValue2 };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
List<double> morphedList = originalList.ReCast();
|
||||||
|
|
||||||
|
// Провоцируем многократное выделение новой памяти (Resize внутреннего массива)
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
morphedList.Add(i * 1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вызываем сборщик мусора, чтобы проверить, не сошел ли он с ума от нашей подмены
|
||||||
|
GC.Collect();
|
||||||
|
GC.WaitForPendingFinalizers();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(102, morphedList.Count);
|
||||||
|
Assert.Equal(NormalValue1, morphedList[0]);
|
||||||
|
Assert.Equal(10 * 1.1, morphedList[12], 5); // Проверка случайного элемента
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 3. Слабое место: Ловушка `ArrayTypeMismatchException` при добавлении в WrapAsList
|
||||||
|
// WrapAsList создает фейковый список, подменяя MethodTable исходного массива на double[].
|
||||||
|
// Но когда мы вызываем List.Add(), рантайм внутри делает Array.Copy().
|
||||||
|
// Если CLR поймет, что исходный массив физически был массивом структур Length,
|
||||||
|
// вылетит ArrayTypeMismatchException.
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WrapAsList_Must_Allow_Adding_Elements_Without_ArrayTypeMismatchException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
Length[] sourceArray = [(Length)NormalValue1, (Length)NormalValue2];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
List<double> wrappedList = sourceArray.WrapAsList();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
// Это действие вызывает внутренний Array.Copy. Самое хрупкое место!
|
||||||
|
var exception = Record.Exception(() => wrappedList.Add(999.99));
|
||||||
|
|
||||||
|
Assert.Null(exception); // Тест провален, если здесь вылетит исключение типа массива
|
||||||
|
Assert.Equal(3, wrappedList.Count);
|
||||||
|
Assert.Equal(999.99, wrappedList[2]);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 4. Слабое место: Выравнивание памяти и макет Nullable типов
|
||||||
|
// Структура Nullable<T> в памяти имеет размер больше, чем T (из-за флага HasValue и выравнивания).
|
||||||
|
// Подмена MethodTable для Nullable<Length>[] в Nullable<double>[] — это огромный риск
|
||||||
|
// смещения байт. Проверяем, что null остается null, а значения не затираются.
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Nullable_Array_ReCast_Should_Not_Corrupt_Flags_And_Values()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
Length?[] source = [(Length)NormalValue1, null, (Length)NormalValue2, null];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double?[] morphed = source.ReCast();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(source.Length, morphed.Length);
|
||||||
|
Assert.Equal(NormalValue1, morphed[0]);
|
||||||
|
Assert.Null(morphed[1]);
|
||||||
|
Assert.Equal(NormalValue2, morphed[2]);
|
||||||
|
Assert.Null(morphed[3]);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 5. Слабое место: In-Place мутация (Побочный эффект "Вуду")
|
||||||
|
// Так как ReCast и WrapAsList меняют MethodTable *оригинального* объекта прямо в куче,
|
||||||
|
// старая ссылка на массив Length[] теперь указывает на объект, который думает, что он double[].
|
||||||
|
// Проверяем, как ведет себя оригинальная переменная после этого хака.
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Verify_InPlace_Mutation_SideEffect_Does_Not_Crash_Old_Reference()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
Length[] originalArray = [(Length)NormalValue1];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double[] morphedArray = originalArray.ReCast();
|
||||||
|
|
||||||
|
// Изменяем элемент через НОВЫЙ массив
|
||||||
|
morphedArray[0] = 777.77;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
// Внимание: из-за жесткой мутации в куче originalArray[0] теперь ТОЖЕ вернет 777.77,
|
||||||
|
// потому что они смотрят на одну память. Главное — чтобы CLR не упал при обращении к старой ссылке.
|
||||||
|
double valueFromOldRef = (double)originalArray[0];
|
||||||
|
|
||||||
|
Assert.Equal(777.77, valueFromOldRef);
|
||||||
|
Assert.Same(originalArray, morphedArray); // Физически это один и тот же объект в памяти
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 6. Слабое место: Фильтры CLR и оптимизации LINQ
|
||||||
|
// Компилятор и JIT часто оптимизируют методы вроде .Select() или .ToArray(),
|
||||||
|
// опираясь на тип MethodTable. Проверяем, съедят ли механизмы LINQ наш "поддельный" тип.
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Morphed_Array_Should_Pass_Through_Linq_And_Native_Sorting_Validations()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
Length[] originalArray = [(Length)NormalValue2, (Length)NormalValue1]; // [100.05, 42.42]
|
||||||
|
|
||||||
|
// Act
|
||||||
|
double[] morphedArray = originalArray.ReCast();
|
||||||
|
|
||||||
|
// 1. Проверка LINQ фильтрации
|
||||||
|
double[] processedViaLinq = [.. morphedArray.Where(x => x > 50.0)];
|
||||||
|
|
||||||
|
Assert.Single(processedViaLinq);
|
||||||
|
Assert.Equal(NormalValue2, processedViaLinq[0]);
|
||||||
|
|
||||||
|
// 2. Проверка работы встроенной нативной сортировки (Array.Sort использует JIT-оптимизации)
|
||||||
|
var sortException = Record.Exception(() => Array.Sort(morphedArray));
|
||||||
|
|
||||||
|
Assert.Null(sortException);
|
||||||
|
Assert.True(morphedArray[0] < morphedArray[1]); // Теперь [42.42, 100.05]
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
292
QWERTYkez.Mensura.Tests/CollectionsDivideExtensions.cs
Normal file
292
QWERTYkez.Mensura.Tests/CollectionsDivideExtensions.cs
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
namespace QWERTYkez.Mensura.Tests
|
||||||
|
{
|
||||||
|
public class CollectionsDivideExtensionsTests
|
||||||
|
{
|
||||||
|
private const double Tolerance = 1e-12;
|
||||||
|
private static readonly Length scalarUnit = Length.Meter; // 1000 mm
|
||||||
|
private static readonly double scalarDouble = 2.0;
|
||||||
|
|
||||||
|
// Коллекции для тестирования: два элемента
|
||||||
|
private static readonly Length[] unitsArray = [Length.Meter, Length._MilliMeter];
|
||||||
|
private static readonly Length?[] nullableUnitsArray = [Length.Meter, null, Length._MilliMeter];
|
||||||
|
private static readonly List<Length> unitsList = [Length.Meter, Length._MilliMeter];
|
||||||
|
private static readonly List<Length?> nullableUnitsList = [Length.Meter, null, Length._MilliMeter];
|
||||||
|
private static readonly double[] doubleArray = [2.0, 3.0];
|
||||||
|
private static readonly double?[] nullableDoubleArray = [2.0, null, 3.0];
|
||||||
|
|
||||||
|
// ====================== 1. T[] / double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_TArray_Double_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = unitsArray.Div<Length>(scalarDouble);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 / 2.0, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1 / 2.0, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 2. T?[] / double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_NullableTArray_Double_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = nullableUnitsArray.Div<Length>(scalarDouble);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(1000 / 2.0, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1 / 2.0, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 3. double / T[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_Double_TArray_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Div<Length>(unitsArray);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(2.0 / 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(2.0 / 1, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 4. double / T?[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_Double_NullableTArray_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Div<Length>(nullableUnitsArray);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(2.0 / 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(2.0 / 1, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 5. List<T> / double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_ListT_Double_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = unitsList.Div<Length>(scalarDouble);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 / 2.0, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1 / 2.0, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 6. List<T?> / double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_ListNullableT_Double_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = nullableUnitsList.Div<Length>(scalarDouble);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 / 2.0, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1 / 2.0, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 7. double / List<T> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_Double_ListT_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Div<Length>(unitsList);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(2.0 / 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(2.0 / 1, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 8. double / List<T?> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_Double_ListNullableT_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Div<Length>(nullableUnitsList);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(2.0 / 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(2.0 / 1, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 9. IReadOnlyCollection<T> / double (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_IReadOnlyCollectionT_Double_Span()
|
||||||
|
{
|
||||||
|
Span<Length> dest = new Length[2];
|
||||||
|
((IReadOnlyCollection<Length>)unitsArray).Div(scalarDouble, dest);
|
||||||
|
Assert.Equal(1000 / 2.0, (double)dest[0], Tolerance);
|
||||||
|
Assert.Equal(1 / 2.0, (double)dest[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 10. IReadOnlyCollection<T?> / double (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_IReadOnlyCollectionNullableT_Double_Span()
|
||||||
|
{
|
||||||
|
Span<Length?> dest = new Length?[3];
|
||||||
|
((IReadOnlyCollection<Length?>)nullableUnitsArray).Div(scalarDouble, dest);
|
||||||
|
Assert.Equal(1000 / 2.0, (double)dest[0]!, Tolerance);
|
||||||
|
Assert.Null(dest[1]);
|
||||||
|
Assert.Equal(1 / 2.0, (double)dest[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 11. double / IReadOnlyCollection<T> (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_Double_IReadOnlyCollectionT_Span()
|
||||||
|
{
|
||||||
|
Span<Length> dest = new Length[2];
|
||||||
|
scalarDouble.Div((IReadOnlyCollection<Length>)unitsArray, dest);
|
||||||
|
Assert.Equal(2.0 / 1000, (double)dest[0], Tolerance);
|
||||||
|
Assert.Equal(2.0 / 1, (double)dest[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 12. double / IReadOnlyCollection<T?> (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_Double_IReadOnlyCollectionNullableT_Span()
|
||||||
|
{
|
||||||
|
Span<Length?> dest = new Length?[3];
|
||||||
|
scalarDouble.Div((IReadOnlyCollection<Length?>)nullableUnitsArray, dest);
|
||||||
|
Assert.Equal(2.0 / 1000, (double)dest[0]!, Tolerance);
|
||||||
|
Assert.Null(dest[1]);
|
||||||
|
Assert.Equal(2.0 / 1, (double)dest[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 13. IEnumerable<T> / double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_IEnumerableT_Double_Returns_IEnumerableT()
|
||||||
|
{
|
||||||
|
var result = ((IEnumerable<Length>)unitsArray).Div<Length>(scalarDouble).ToList();
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 / 2.0, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1 / 2.0, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 14. IEnumerable<T?> / double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_IEnumerableNullableT_Double_Returns_IEnumerableNullableT()
|
||||||
|
{
|
||||||
|
var result = ((IEnumerable<Length?>)nullableUnitsArray).Div<Length>(scalarDouble).ToList();
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 / 2.0, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1 / 2.0, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 15. double / IEnumerable<T> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_Double_IEnumerableT_Returns_IEnumerableT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Div<Length>((IEnumerable<Length>)unitsArray).ToList();
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(2.0 / 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(2.0 / 1, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 16. double / IEnumerable<T?> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_Double_IEnumerableNullableT_Returns_IEnumerableNullableT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Div<Length>((IEnumerable<Length?>)nullableUnitsArray).ToList();
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(2.0 / 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(2.0 / 1, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 17. double[] / T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_DoubleArray_T_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = doubleArray.Div(scalarUnit);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(2.0 / 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(3.0 / 1000, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 18. double?[] / T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_NullableDoubleArray_T_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = nullableDoubleArray.Div(scalarUnit);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(2.0 / 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(3.0 / 1000, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 19. T / double[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_T_DoubleArray_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Div(doubleArray);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 / 2.0, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1000 / 3.0, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 20. T / double?[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_T_NullableDoubleArray_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Div(nullableDoubleArray);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(1000 / 2.0, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1000 / 3.0, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 21. List<double> / T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_ListDouble_T_Returns_ListT()
|
||||||
|
{
|
||||||
|
var list = new List<double> { 2.0, 3.0 };
|
||||||
|
var result = list.Div(scalarUnit);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(2.0 / 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(3.0 / 1000, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 22. List<double?> / T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_ListNullableDouble_T_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var list = new List<double?> { 2.0, null, 3.0 };
|
||||||
|
var result = list.Div(scalarUnit);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(2.0 / 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(3.0 / 1000, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 23. T / List<double> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_T_ListDouble_Returns_ListT()
|
||||||
|
{
|
||||||
|
var list = new List<double> { 2.0, 3.0 };
|
||||||
|
var result = scalarUnit.Div(list);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 / 2.0, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1000 / 3.0, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 24. T / List<double?> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_T_ListNullableDouble_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var list = new List<double?> { 2.0, null, 3.0 };
|
||||||
|
var result = scalarUnit.Div(list);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 / 2.0, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1000 / 3.0, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 25. T / T[] -> double[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_T_TArray_Returns_DoubleArray()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Div(unitsArray);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 / 1000.0, result[0], Tolerance);
|
||||||
|
Assert.Equal(1000 / 1.0, result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== Дополнительно: пустые коллекции, null аргументы ======================
|
||||||
|
[Fact]
|
||||||
|
public void Div_EmptyArray_ReturnsEmptyArray()
|
||||||
|
{
|
||||||
|
var empty = Array.Empty<Length>();
|
||||||
|
var result = empty.Div<Length>(2.0);
|
||||||
|
Assert.Empty(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
337
QWERTYkez.Mensura.Tests/CollectionsMinusExtensions.cs
Normal file
337
QWERTYkez.Mensura.Tests/CollectionsMinusExtensions.cs
Normal file
@@ -0,0 +1,337 @@
|
|||||||
|
namespace QWERTYkez.Mensura.Tests
|
||||||
|
{
|
||||||
|
public class CollectionsMinusExtensionsTests
|
||||||
|
{
|
||||||
|
private const double Tolerance = 1e-12;
|
||||||
|
private static readonly Length scalarUnit = Length.Meter; // 1000 mm
|
||||||
|
private static readonly double scalarDouble = 1000.0; // уменьшаемое/вычитаемое в мм
|
||||||
|
|
||||||
|
// Коллекции единиц
|
||||||
|
private static readonly Length[] unitsArray = [Length.Meter, Length._MilliMeter];
|
||||||
|
private static readonly Length?[] nullableUnitsArray = [Length.Meter, null, Length._MilliMeter];
|
||||||
|
private static readonly List<Length> unitsList = [Length.Meter, Length._MilliMeter];
|
||||||
|
private static readonly List<Length?> nullableUnitsList = [Length.Meter, null, Length._MilliMeter];
|
||||||
|
|
||||||
|
// Коллекции double
|
||||||
|
private static readonly double[] doubleArray = [500.0, 200.0]; // мм
|
||||||
|
private static readonly double?[] nullableDoubleArray = [500.0, null, 200.0];
|
||||||
|
private static readonly List<double> doubleList = [500.0, 200.0];
|
||||||
|
private static readonly List<double?> nullableDoubleList = [500.0, null, 200.0];
|
||||||
|
|
||||||
|
// ====================== 1. T[] - double (результат T[]) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_TArray_Double_Returns_TArray()
|
||||||
|
{
|
||||||
|
// units - subtrahend
|
||||||
|
var result = unitsArray.Minus<Length>(scalarDouble);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 - 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1 - 1000, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Minus_TArray_Double_ByZero_Works()
|
||||||
|
{
|
||||||
|
var result = unitsArray.Minus<Length>(0.0);
|
||||||
|
Assert.Equal(1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 2. T?[] - double (результат T?[]) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_NullableTArray_Double_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = nullableUnitsArray.Minus<Length>(scalarDouble);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(1000 - 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1 - 1000, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 3. double - T[] (результат T[]) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_Double_TArray_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Minus<Length>(unitsArray);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 - 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1000 - 1, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 4. double - T?[] (результат T?[]) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_Double_NullableTArray_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Minus<Length>(nullableUnitsArray);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(1000 - 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1000 - 1, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 5. List<T> - double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_ListT_Double_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = unitsList.Minus<Length>(scalarDouble);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 - 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1 - 1000, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 6. List<T?> - double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_ListNullableT_Double_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = nullableUnitsList.Minus<Length>(scalarDouble);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 - 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1 - 1000, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 7. double - List<T> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_Double_ListT_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Minus<Length>(unitsList);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 - 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1000 - 1, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 8. double - List<T?> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_Double_ListNullableT_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Minus<Length>(nullableUnitsList);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 - 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1000 - 1, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 9. IReadOnlyCollection<T> - double (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_IReadOnlyCollectionT_Double_Span()
|
||||||
|
{
|
||||||
|
Span<Length> dest = new Length[2];
|
||||||
|
((IReadOnlyCollection<Length>)unitsArray).Minus<Length>(scalarDouble, dest);
|
||||||
|
Assert.Equal(1000 - 1000, (double)dest[0], Tolerance);
|
||||||
|
Assert.Equal(1 - 1000, (double)dest[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 10. IReadOnlyCollection<T?> - double (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_IReadOnlyCollectionNullableT_Double_Span()
|
||||||
|
{
|
||||||
|
Span<Length?> dest = new Length?[3];
|
||||||
|
((IReadOnlyCollection<Length?>)nullableUnitsArray).Minus<Length>(scalarDouble, dest);
|
||||||
|
Assert.Equal(1000 - 1000, (double)dest[0]!, Tolerance);
|
||||||
|
Assert.Null(dest[1]);
|
||||||
|
Assert.Equal(1 - 1000, (double)dest[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 11. double - IReadOnlyCollection<T> (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_Double_IReadOnlyCollectionT_Span()
|
||||||
|
{
|
||||||
|
Span<Length> dest = new Length[2];
|
||||||
|
scalarDouble.Minus<Length>((IReadOnlyCollection<Length>)unitsArray, dest);
|
||||||
|
Assert.Equal(1000 - 1000, (double)dest[0], Tolerance);
|
||||||
|
Assert.Equal(1000 - 1, (double)dest[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 12. double - IReadOnlyCollection<T?> (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_Double_IReadOnlyCollectionNullableT_Span()
|
||||||
|
{
|
||||||
|
Span<Length?> dest = new Length?[3];
|
||||||
|
scalarDouble.Minus<Length>((IReadOnlyCollection<Length?>)nullableUnitsArray, dest);
|
||||||
|
Assert.Equal(1000 - 1000, (double)dest[0]!, Tolerance);
|
||||||
|
Assert.Null(dest[1]);
|
||||||
|
Assert.Equal(1000 - 1, (double)dest[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 13. IEnumerable<T> - double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_IEnumerableT_Double_Returns_IEnumerableT()
|
||||||
|
{
|
||||||
|
var result = ((IEnumerable<Length>)unitsArray).Minus<Length>(scalarDouble).ToList();
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 - 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1 - 1000, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 14. IEnumerable<T?> - double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_IEnumerableNullableT_Double_Returns_IEnumerableNullableT()
|
||||||
|
{
|
||||||
|
var result = ((IEnumerable<Length?>)nullableUnitsArray).Minus<Length>(scalarDouble).ToList();
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 - 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1 - 1000, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 15. double - IEnumerable<T> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_Double_IEnumerableT_Returns_IEnumerableT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Minus<Length>((IEnumerable<Length>)unitsArray).ToList();
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 - 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1000 - 1, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 16. double - IEnumerable<T?> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_Double_IEnumerableNullableT_Returns_IEnumerableNullableT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Minus<Length>((IEnumerable<Length?>)nullableUnitsArray).ToList();
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 - 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1000 - 1, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 17. double[] - T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_DoubleArray_T_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = doubleArray.Minus(scalarUnit);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(500 - 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(200 - 1000, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 18. double?[] - T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_NullableDoubleArray_T_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = nullableDoubleArray.Minus(scalarUnit);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(500 - 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(200 - 1000, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 19. T - double[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_T_DoubleArray_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Minus(doubleArray);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 - 500, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1000 - 200, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 20. T - double?[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_T_NullableDoubleArray_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Minus(nullableDoubleArray);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(1000 - 500, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1000 - 200, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 21. List<double> - T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_ListDouble_T_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = doubleList.Minus(scalarUnit);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(500 - 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(200 - 1000, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 22. List<double?> - T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_ListNullableDouble_T_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = nullableDoubleList.Minus(scalarUnit);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(500 - 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(200 - 1000, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 23. T - List<double> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_T_ListDouble_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Minus(doubleList);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 - 500, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1000 - 200, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 24. T - List<double?> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_T_ListNullableDouble_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Minus(nullableDoubleList);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 - 500, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1000 - 200, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 25. T - T[] -> double[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Minus_T_TArray_Returns_DoubleArray()
|
||||||
|
{
|
||||||
|
var result = scalarUnit - unitsArray;
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 - 1000, result[0]._Value, Tolerance);
|
||||||
|
Assert.Equal(1000 - 1, result[1]._Value, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Дополнительно: перегрузки, где результат double (без указания R)
|
||||||
|
// Тестируем Minus<T>(T[] units, T subtrahend) – возвращает double[]
|
||||||
|
[Fact]
|
||||||
|
public void Minus_TArray_T_Returns_DoubleArray()
|
||||||
|
{
|
||||||
|
var result = unitsArray - scalarUnit;
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 - 1000, result[0]._Value, Tolerance);
|
||||||
|
Assert.Equal(1 - 1000, result[1]._Value, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Minus_ListT_T_Returns_DoubleList()
|
||||||
|
{
|
||||||
|
var result = unitsList - scalarUnit;
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 - 1000, result[0]._Value, Tolerance);
|
||||||
|
Assert.Equal(1 - 1000, result[1]._Value, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка пустых коллекций
|
||||||
|
[Fact]
|
||||||
|
public void Minus_EmptyArray_ReturnsEmptyArray()
|
||||||
|
{
|
||||||
|
var empty = Array.Empty<Length>();
|
||||||
|
var result = empty.Minus<Length>(5.0);
|
||||||
|
Assert.Empty(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Minus_NullArray_ReturnsNull()
|
||||||
|
{
|
||||||
|
Length[] nullArray = null!;
|
||||||
|
var result = nullArray.Minus<Length>(5.0);
|
||||||
|
Assert.Null(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Minus_NullList_ReturnsNull()
|
||||||
|
{
|
||||||
|
List<Length> nullList = null!;
|
||||||
|
var result = nullList.Minus<Length>(5.0);
|
||||||
|
Assert.Null(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
335
QWERTYkez.Mensura.Tests/CollectionsMultiplyExtensions.cs
Normal file
335
QWERTYkez.Mensura.Tests/CollectionsMultiplyExtensions.cs
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
namespace QWERTYkez.Mensura.Tests
|
||||||
|
{
|
||||||
|
public class CollectionsMultiplyExtensionsTests
|
||||||
|
{
|
||||||
|
private const double Tolerance = 1e-12;
|
||||||
|
private static readonly Length scalarUnit = Length.Meter; // 1000 mm
|
||||||
|
private static readonly double scalarDouble = 2.0;
|
||||||
|
|
||||||
|
// Коллекции единиц
|
||||||
|
private static readonly Length[] unitsArray = [Length.Meter, Length._MilliMeter];
|
||||||
|
private static readonly Length?[] nullableUnitsArray = [Length.Meter, null, Length._MilliMeter];
|
||||||
|
private static readonly List<Length> unitsList = [Length.Meter, Length._MilliMeter];
|
||||||
|
private static readonly List<Length?> nullableUnitsList = [Length.Meter, null, Length._MilliMeter];
|
||||||
|
|
||||||
|
// Коллекции double
|
||||||
|
private static readonly double[] doubleArray = [5.0, 3.0];
|
||||||
|
private static readonly double?[] nullableDoubleArray = [5.0, null, 3.0];
|
||||||
|
private static readonly List<double> doubleList = [5.0, 3.0];
|
||||||
|
private static readonly List<double?> nullableDoubleList = [5.0, null, 3.0];
|
||||||
|
|
||||||
|
// ====================== 1. T[] * double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_TArray_Double_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = unitsArray.Mul<Length>(scalarDouble);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 * 2, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1 * 2, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Mul_TArray_Double_ByZero_Works()
|
||||||
|
{
|
||||||
|
var result = unitsArray.Mul<Length>(0.0);
|
||||||
|
Assert.Equal(0, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(0, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 2. T?[] * double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_NullableTArray_Double_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = nullableUnitsArray.Mul<Length>(scalarDouble);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(1000 * 2, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // null * 2 = null
|
||||||
|
Assert.Equal(1 * 2, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 3. double * T[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_Double_TArray_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Mul<Length>(unitsArray);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(2 * 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(2 * 1, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 4. double * T?[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_Double_NullableTArray_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Mul<Length>(nullableUnitsArray);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(2 * 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // 2 * null = null
|
||||||
|
Assert.Equal(2 * 1, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 5. List<T> * double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_ListT_Double_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = unitsList.Mul<Length>(scalarDouble);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 * 2, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1 * 2, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 6. List<T?> * double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_ListNullableT_Double_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = nullableUnitsList.Mul<Length>(scalarDouble);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 * 2, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // null * 2 = null
|
||||||
|
Assert.Equal(1 * 2, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 7. double * List<T> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_Double_ListT_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Mul<Length>(unitsList);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(2 * 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(2 * 1, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 8. double * List<T?> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_Double_ListNullableT_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Mul<Length>(nullableUnitsList);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(2 * 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // 2 * null = null
|
||||||
|
Assert.Equal(2 * 1, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 9. IReadOnlyCollection<T> * double (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_IReadOnlyCollectionT_Double_Span()
|
||||||
|
{
|
||||||
|
Span<Length> dest = new Length[2];
|
||||||
|
((IReadOnlyCollection<Length>)unitsArray).Mul<Length>(scalarDouble, dest);
|
||||||
|
Assert.Equal(1000 * 2, (double)dest[0], Tolerance);
|
||||||
|
Assert.Equal(1 * 2, (double)dest[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 10. IReadOnlyCollection<T?> * double (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_IReadOnlyCollectionNullableT_Double_Span()
|
||||||
|
{
|
||||||
|
Span<Length?> dest = new Length?[3];
|
||||||
|
((IReadOnlyCollection<Length?>)nullableUnitsArray).Mul<Length>(scalarDouble, dest);
|
||||||
|
Assert.Equal(1000 * 2, (double)dest[0]!, Tolerance);
|
||||||
|
Assert.Null(dest[1]); // null * 2 = null
|
||||||
|
Assert.Equal(1 * 2, (double)dest[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 11. double * IReadOnlyCollection<T> (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_Double_IReadOnlyCollectionT_Span()
|
||||||
|
{
|
||||||
|
Span<Length> dest = new Length[2];
|
||||||
|
scalarDouble.Mul<Length>((IReadOnlyCollection<Length>)unitsArray, dest);
|
||||||
|
Assert.Equal(2 * 1000, (double)dest[0], Tolerance);
|
||||||
|
Assert.Equal(2 * 1, (double)dest[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 12. double * IReadOnlyCollection<T?> (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_Double_IReadOnlyCollectionNullableT_Span()
|
||||||
|
{
|
||||||
|
Span<Length?> dest = new Length?[3];
|
||||||
|
scalarDouble.Mul<Length>((IReadOnlyCollection<Length?>)nullableUnitsArray, dest);
|
||||||
|
Assert.Equal(2 * 1000, (double)dest[0]!, Tolerance);
|
||||||
|
Assert.Null(dest[1]); // 2 * null = null
|
||||||
|
Assert.Equal(2 * 1, (double)dest[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 13. IEnumerable<T> * double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_IEnumerableT_Double_Returns_IEnumerableT()
|
||||||
|
{
|
||||||
|
var result = ((IEnumerable<Length>)unitsArray).Mul<Length>(scalarDouble).ToList();
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 * 2, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1 * 2, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 14. IEnumerable<T?> * double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_IEnumerableNullableT_Double_Returns_IEnumerableNullableT()
|
||||||
|
{
|
||||||
|
var result = ((IEnumerable<Length?>)nullableUnitsArray).Mul<Length>(scalarDouble).ToList();
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 * 2, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // null * 2 = null
|
||||||
|
Assert.Equal(1 * 2, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 15. double * IEnumerable<T> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_Double_IEnumerableT_Returns_IEnumerableT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Mul<Length>((IEnumerable<Length>)unitsArray).ToList();
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(2 * 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(2 * 1, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 16. double * IEnumerable<T?> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_Double_IEnumerableNullableT_Returns_IEnumerableNullableT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Mul<Length>((IEnumerable<Length?>)nullableUnitsArray).ToList();
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(2 * 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // 2 * null = null
|
||||||
|
Assert.Equal(2 * 1, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 17. double[] * T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_DoubleArray_T_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = doubleArray.Mul(scalarUnit);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(5 * 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(3 * 1000, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 18. double?[] * T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_NullableDoubleArray_T_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = nullableDoubleArray.Mul(scalarUnit);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(5 * 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // null * Length = null
|
||||||
|
Assert.Equal(3 * 1000, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 19. T * double[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_T_DoubleArray_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Mul(doubleArray);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 * 5, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1000 * 3, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 20. T * double?[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_T_NullableDoubleArray_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Mul(nullableDoubleArray);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(1000 * 5, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // Length * null = null
|
||||||
|
Assert.Equal(1000 * 3, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 21. List<double> * T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_ListDouble_T_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = doubleList.Mul(scalarUnit);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(5 * 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(3 * 1000, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 22. List<double?> * T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_ListNullableDouble_T_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = nullableDoubleList.Mul(scalarUnit);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(5 * 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // null * Length = null
|
||||||
|
Assert.Equal(3 * 1000, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 23. T * List<double> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_T_ListDouble_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Mul(doubleList);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 * 5, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1000 * 3, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 24. T * List<double?> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_T_ListNullableDouble_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Mul(nullableDoubleList);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 * 5, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // Length * null = null
|
||||||
|
Assert.Equal(1000 * 3, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 25. T * T[] -> double[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_T_TArray_Returns_DoubleArray()
|
||||||
|
{
|
||||||
|
var result = scalarUnit * unitsArray;
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 * 1000, result[0]._Value, Tolerance);
|
||||||
|
Assert.Equal(1000 * 1, result[1]._Value, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Дополнительно: перегрузки с результатом double (без R)
|
||||||
|
[Fact]
|
||||||
|
public void Mul_TArray_T_Returns_DoubleArray()
|
||||||
|
{
|
||||||
|
var result = unitsArray * scalarUnit;
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 * 1000, result[0]._Value, Tolerance);
|
||||||
|
Assert.Equal(1 * 1000, result[1]._Value, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Mul_ListT_T_Returns_DoubleList()
|
||||||
|
{
|
||||||
|
var result = unitsList * scalarUnit;
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 * 1000, result[0]._Value, Tolerance);
|
||||||
|
Assert.Equal(1 * 1000, result[1]._Value, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== Обработка null коллекций ======================
|
||||||
|
[Fact]
|
||||||
|
public void Mul_NullArray_ReturnsNull()
|
||||||
|
{
|
||||||
|
Length[] nullArray = null!;
|
||||||
|
var result = nullArray.Mul<Length>(5.0);
|
||||||
|
Assert.Null(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Mul_NullList_ReturnsNull()
|
||||||
|
{
|
||||||
|
List<Length> nullList = null!;
|
||||||
|
var result = nullList.Mul<Length>(5.0);
|
||||||
|
Assert.Null(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Mul_EmptyArray_ReturnsEmptyArray()
|
||||||
|
{
|
||||||
|
var empty = Array.Empty<Length>();
|
||||||
|
var result = empty.Mul<Length>(5.0);
|
||||||
|
Assert.Empty(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
334
QWERTYkez.Mensura.Tests/CollectionsPlusExtensions.cs
Normal file
334
QWERTYkez.Mensura.Tests/CollectionsPlusExtensions.cs
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using QWERTYkez.Mensura.Units;
|
||||||
|
using QWERTYkez.Mensura.Extensions;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace QWERTYkez.Mensura.Tests
|
||||||
|
{
|
||||||
|
public class CollectionsPlusExtensionsTests
|
||||||
|
{
|
||||||
|
private const double Tolerance = 1e-12;
|
||||||
|
private static readonly Length scalarUnit = Length.Meter; // 1000 mm
|
||||||
|
private static readonly double scalarDouble = 500.0; // прибавляемое значение в мм
|
||||||
|
|
||||||
|
// Коллекции единиц
|
||||||
|
private static readonly Length[] unitsArray = new[] { Length.Meter, Length._MilliMeter };
|
||||||
|
private static readonly Length?[] nullableUnitsArray = new Length?[] { Length.Meter, null, Length._MilliMeter };
|
||||||
|
private static readonly List<Length> unitsList = new List<Length> { Length.Meter, Length._MilliMeter };
|
||||||
|
private static readonly List<Length?> nullableUnitsList = new List<Length?> { Length.Meter, null, Length._MilliMeter };
|
||||||
|
|
||||||
|
// Коллекции double
|
||||||
|
private static readonly double[] doubleArray = new double[] { 200.0, 300.0 };
|
||||||
|
private static readonly double?[] nullableDoubleArray = new double?[] { 200.0, null, 300.0 };
|
||||||
|
private static readonly List<double> doubleList = new List<double> { 200.0, 300.0 };
|
||||||
|
private static readonly List<double?> nullableDoubleList = new List<double?> { 200.0, null, 300.0 };
|
||||||
|
|
||||||
|
// ====================== 1. T[] + double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_TArray_Double_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = unitsArray.Plus<Length>(scalarDouble);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 + 500, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1 + 500, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 2. T?[] + double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_NullableTArray_Double_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = nullableUnitsArray.Plus<Length>(scalarDouble);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(1000 + 500, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // null + число = null
|
||||||
|
Assert.Equal(1 + 500, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 3. double + T[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_Double_TArray_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Plus<Length>(unitsArray);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(500 + 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(500 + 1, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 4. double + T?[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_Double_NullableTArray_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Plus<Length>(nullableUnitsArray);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(500 + 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // число + null = null
|
||||||
|
Assert.Equal(500 + 1, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 5. List<T> + double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_ListT_Double_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = unitsList.Plus<Length>(scalarDouble);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 + 500, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1 + 500, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 6. List<T?> + double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_ListNullableT_Double_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = nullableUnitsList.Plus<Length>(scalarDouble);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 + 500, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // null + число = null
|
||||||
|
Assert.Equal(1 + 500, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 7. double + List<T> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_Double_ListT_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Plus<Length>(unitsList);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(500 + 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(500 + 1, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 8. double + List<T?> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_Double_ListNullableT_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Plus<Length>(nullableUnitsList);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(500 + 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // число + null = null
|
||||||
|
Assert.Equal(500 + 1, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 9. IReadOnlyCollection<T> + double (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_IReadOnlyCollectionT_Double_Span()
|
||||||
|
{
|
||||||
|
Span<Length> dest = new Length[2];
|
||||||
|
((IReadOnlyCollection<Length>)unitsArray).Plus<Length>(scalarDouble, dest);
|
||||||
|
Assert.Equal(1000 + 500, (double)dest[0], Tolerance);
|
||||||
|
Assert.Equal(1 + 500, (double)dest[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 10. IReadOnlyCollection<T?> + double (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_IReadOnlyCollectionNullableT_Double_Span()
|
||||||
|
{
|
||||||
|
Span<Length?> dest = new Length?[3];
|
||||||
|
((IReadOnlyCollection<Length?>)nullableUnitsArray).Plus<Length>(scalarDouble, dest);
|
||||||
|
Assert.Equal(1000 + 500, (double)dest[0]!, Tolerance);
|
||||||
|
Assert.Null(dest[1]); // null + число = null
|
||||||
|
Assert.Equal(1 + 500, (double)dest[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 11. double + IReadOnlyCollection<T> (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_Double_IReadOnlyCollectionT_Span()
|
||||||
|
{
|
||||||
|
Span<Length> dest = new Length[2];
|
||||||
|
scalarDouble.Plus<Length>((IReadOnlyCollection<Length>)unitsArray, dest);
|
||||||
|
Assert.Equal(500 + 1000, (double)dest[0], Tolerance);
|
||||||
|
Assert.Equal(500 + 1, (double)dest[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 12. double + IReadOnlyCollection<T?> (Span) ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_Double_IReadOnlyCollectionNullableT_Span()
|
||||||
|
{
|
||||||
|
Span<Length?> dest = new Length?[3];
|
||||||
|
scalarDouble.Plus<Length>((IReadOnlyCollection<Length?>)nullableUnitsArray, dest);
|
||||||
|
Assert.Equal(500 + 1000, (double)dest[0]!, Tolerance);
|
||||||
|
Assert.Null(dest[1]); // число + null = null
|
||||||
|
Assert.Equal(500 + 1, (double)dest[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 13. IEnumerable<T> + double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_IEnumerableT_Double_Returns_IEnumerableT()
|
||||||
|
{
|
||||||
|
var result = ((IEnumerable<Length>)unitsArray).Plus<Length>(scalarDouble).ToList();
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 + 500, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1 + 500, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 14. IEnumerable<T?> + double ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_IEnumerableNullableT_Double_Returns_IEnumerableNullableT()
|
||||||
|
{
|
||||||
|
var result = ((IEnumerable<Length?>)nullableUnitsArray).Plus<Length>(scalarDouble).ToList();
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 + 500, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // null + число = null
|
||||||
|
Assert.Equal(1 + 500, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 15. double + IEnumerable<T> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_Double_IEnumerableT_Returns_IEnumerableT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Plus<Length>((IEnumerable<Length>)unitsArray).ToList();
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(500 + 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(500 + 1, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 16. double + IEnumerable<T?> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_Double_IEnumerableNullableT_Returns_IEnumerableNullableT()
|
||||||
|
{
|
||||||
|
var result = scalarDouble.Plus<Length>((IEnumerable<Length?>)nullableUnitsArray).ToList();
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(500 + 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // число + null = null
|
||||||
|
Assert.Equal(500 + 1, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 17. double[] + T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_DoubleArray_T_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = doubleArray.Plus(scalarUnit);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(200 + 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(300 + 1000, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 18. double?[] + T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_NullableDoubleArray_T_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = nullableDoubleArray.Plus(scalarUnit);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(200 + 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // null + Length = null
|
||||||
|
Assert.Equal(300 + 1000, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 19. T + double[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_T_DoubleArray_Returns_TArray()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Plus(doubleArray);
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 + 200, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1000 + 300, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 20. T + double?[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_T_NullableDoubleArray_Returns_NullableTArray()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Plus(nullableDoubleArray);
|
||||||
|
Assert.Equal(3, result.Length);
|
||||||
|
Assert.Equal(1000 + 200, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // Length + null = null
|
||||||
|
Assert.Equal(1000 + 300, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 21. List<double> + T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_ListDouble_T_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = doubleList.Plus(scalarUnit);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(200 + 1000, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(300 + 1000, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 22. List<double?> + T ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_ListNullableDouble_T_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = nullableDoubleList.Plus(scalarUnit);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(200 + 1000, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // null + Length = null
|
||||||
|
Assert.Equal(300 + 1000, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 23. T + List<double> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_T_ListDouble_Returns_ListT()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Plus(doubleList);
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 + 200, (double)result[0], Tolerance);
|
||||||
|
Assert.Equal(1000 + 300, (double)result[1], Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 24. T + List<double?> ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_T_ListNullableDouble_Returns_ListNullableT()
|
||||||
|
{
|
||||||
|
var result = scalarUnit.Plus(nullableDoubleList);
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1000 + 200, (double)result[0]!, Tolerance);
|
||||||
|
Assert.Null(result[1]); // Length + null = null
|
||||||
|
Assert.Equal(1000 + 300, (double)result[2]!, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 25. T + T[] -> double[] ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_T_TArray_Returns_DoubleArray()
|
||||||
|
{
|
||||||
|
var result = scalarUnit + unitsArray;
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 + 1000, result[0]._Value, Tolerance);
|
||||||
|
Assert.Equal(1000 + 1, result[1]._Value, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Дополнительно: перегрузки с результатом double (без R)
|
||||||
|
[Fact]
|
||||||
|
public void Plus_TArray_T_Returns_DoubleArray()
|
||||||
|
{
|
||||||
|
var result = unitsArray + scalarUnit;
|
||||||
|
Assert.Equal(2, result.Length);
|
||||||
|
Assert.Equal(1000 + 1000, result[0]._Value, Tolerance);
|
||||||
|
Assert.Equal(1 + 1000, result[1]._Value, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Plus_ListT_T_Returns_DoubleList()
|
||||||
|
{
|
||||||
|
var result = unitsList + scalarUnit;
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1000 + 1000, result[0]._Value, Tolerance);
|
||||||
|
Assert.Equal(1 + 1000, result[1]._Value, Tolerance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== Обработка null коллекций ======================
|
||||||
|
[Fact]
|
||||||
|
public void Plus_NullArray_ReturnsNull()
|
||||||
|
{
|
||||||
|
Length[] nullArray = null;
|
||||||
|
var result = nullArray.Plus<Length>(5.0);
|
||||||
|
Assert.Null(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Plus_NullList_ReturnsNull()
|
||||||
|
{
|
||||||
|
List<Length> nullList = null;
|
||||||
|
var result = nullList.Plus<Length>(5.0);
|
||||||
|
Assert.Null(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Plus_EmptyArray_ReturnsEmptyArray()
|
||||||
|
{
|
||||||
|
var empty = Array.Empty<Length>();
|
||||||
|
var result = empty.Plus<Length>(5.0);
|
||||||
|
Assert.Empty(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
QWERTYkez.Mensura.Tests/CollectionsPow2Extensions.cs
Normal file
73
QWERTYkez.Mensura.Tests/CollectionsPow2Extensions.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
namespace QWERTYkez.Mensura.Tests;
|
||||||
|
|
||||||
|
public class CollectionsPow2Extensions
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Pow2_Array_CalculatesCorrectly()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
Length[] source = [new(2), new(3), new(10)];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
Length[] result = source.Pow2<Length, Length>();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(4, result[0]._Value);
|
||||||
|
Assert.Equal(9, result[1]._Value);
|
||||||
|
Assert.Equal(100, result[2]._Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Pow2_NullableArray_HandlesNulls()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
Length?[] source = [new(5), null, new(4)];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
Length?[] result = source.Pow2<Length, Length>();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(25, result[0]?._Value);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(16, result[2]?._Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Pow2_List_ReturnsCorrectResult()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var source = new List<Length> { new(2), new(8) };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = source.Pow2<Length, Length>();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(4, result[0]._Value);
|
||||||
|
Assert.Equal(64, result[1]._Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Pow2_IEnumerable_ProcessesCorrectly()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
IEnumerable<Length> source = new HashSet<Length> { new(3), new(7) };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = source.Pow2<Length, Length>().ToList();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Contains(result, x => x._Value == 9);
|
||||||
|
Assert.Contains(result, x => x._Value == 49);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Pow2_DestinationTooShort_ThrowsArgumentException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
Length[] source = [new(2), new(3)];
|
||||||
|
Length[] dest = new Length[1];
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.Throws<ArgumentException>(() => source.Pow2(dest));
|
||||||
|
}
|
||||||
|
}
|
||||||
59
QWERTYkez.Mensura.Tests/CollectionsPow3Extensions.cs
Normal file
59
QWERTYkez.Mensura.Tests/CollectionsPow3Extensions.cs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
namespace QWERTYkez.Mensura.Tests;
|
||||||
|
|
||||||
|
public class Pow3ExtensionsTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Pow3_Array_CalculatesCorrectly()
|
||||||
|
{
|
||||||
|
// Arrange: 2^3=8, 3^3=27, 4^3=64
|
||||||
|
Length[] source = [new(2), new(3), new(4)];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
Length[] result = source.Pow3<Length, Length>();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(8, result[0]._Value);
|
||||||
|
Assert.Equal(27, result[1]._Value);
|
||||||
|
Assert.Equal(64, result[2]._Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Pow3_NullableArray_HandlesNulls()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
Length?[] source = [new(5), null, new(10)];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
Length?[] result = source.Pow3<Length, Length>();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(125, result[0]?._Value);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(1000, result[2]?._Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Pow3_List_ReturnsCorrectResult()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var source = new List<Length> { new(2), new(5) };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = source.Pow3<Length, Length>();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(8, result[0]._Value);
|
||||||
|
Assert.Equal(125, result[1]._Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Pow3_DestinationTooShort_ThrowsArgumentException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
Length[] source = [new(2), new(3)];
|
||||||
|
Length[] dest = new Length[1];
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.Throws<ArgumentException>(() => source.Pow3(dest));
|
||||||
|
}
|
||||||
|
}
|
||||||
75
QWERTYkez.Mensura.Tests/CollectionsPowNExtensions.cs
Normal file
75
QWERTYkez.Mensura.Tests/CollectionsPowNExtensions.cs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
namespace QWERTYkez.Mensura.Tests;
|
||||||
|
|
||||||
|
public class CollectionsPowNExtensions
|
||||||
|
{
|
||||||
|
private const double BaseVal = 3.0;
|
||||||
|
private const double Expected = 9.0; // 3^2 = 9
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Test_PowN()
|
||||||
|
{
|
||||||
|
Length[] arr = [new(BaseVal)];
|
||||||
|
Length?[] arrNull = [new(BaseVal), null];
|
||||||
|
List<Length> list = [new(BaseVal)];
|
||||||
|
List<Length?> listNull = [new(BaseVal), null];
|
||||||
|
IReadOnlyCollection<Length> roc = list;
|
||||||
|
IEnumerable<Length> en = list;
|
||||||
|
IEnumerable<Length?> enNull = listNull;
|
||||||
|
|
||||||
|
// --- 1. Целые степени (int) ---
|
||||||
|
// Span-based Core
|
||||||
|
Span<Length> dstSpan = new Length[1];
|
||||||
|
arr.AsSpan().PowCore(2, 1, dstSpan);
|
||||||
|
Assert.Equal(Expected, dstSpan[0]._Value);
|
||||||
|
|
||||||
|
arrNull.AsSpan().PowCore(2, 2, new Length?[2]); // Проверка nullable span
|
||||||
|
|
||||||
|
arr.AsSpan().Pow(2, dstSpan);
|
||||||
|
Assert.Equal(Expected, dstSpan[0]._Value);
|
||||||
|
|
||||||
|
// Arrays
|
||||||
|
Assert.Equal(Expected, arr.Pow<Length, Length>(2)[0]._Value);
|
||||||
|
Assert.Equal(Expected, arrNull.Pow<Length, Length>(2)[0]?._Value);
|
||||||
|
|
||||||
|
// Lists
|
||||||
|
Assert.Equal(Expected, list.Pow<Length, Length>(2)[0]._Value);
|
||||||
|
Assert.Equal(Expected, listNull.Pow<Length, Length>(2)[0]?._Value);
|
||||||
|
|
||||||
|
// ReadOnlyCollection
|
||||||
|
roc.Pow(2, dstSpan);
|
||||||
|
Assert.Equal(Expected, dstSpan[0]._Value);
|
||||||
|
|
||||||
|
// IEnumerable / Iterators
|
||||||
|
Assert.Equal(Expected, en.Pow<Length, Length>(2).First()._Value);
|
||||||
|
Assert.Equal(Expected, enNull.Pow<Length, Length>(2).First(x => x.HasValue)?._Value);
|
||||||
|
|
||||||
|
|
||||||
|
// --- 2. Дробные степени (double) ---
|
||||||
|
// Span-based Core
|
||||||
|
arr.AsSpan().PowCore(2.0, 1, dstSpan);
|
||||||
|
Assert.Equal(Expected, dstSpan[0]._Value);
|
||||||
|
|
||||||
|
arr.AsSpan().Pow(2.0, dstSpan);
|
||||||
|
Assert.Equal(Expected, dstSpan[0]._Value);
|
||||||
|
|
||||||
|
// Arrays
|
||||||
|
Assert.Equal(Expected, arr.Pow<Length, Length>(2.0)[0]._Value);
|
||||||
|
Assert.Equal(Expected, arrNull.Pow<Length, Length>(2.0)[0]?._Value);
|
||||||
|
|
||||||
|
// Lists
|
||||||
|
Assert.Equal(Expected, list.Pow<Length, Length>(2.0)[0]._Value);
|
||||||
|
Assert.Equal(Expected, listNull.Pow<Length, Length>(2.0)[0]?._Value);
|
||||||
|
|
||||||
|
// ReadOnlyCollection
|
||||||
|
roc.Pow(2.0, dstSpan);
|
||||||
|
Assert.Equal(Expected, dstSpan[0]._Value);
|
||||||
|
|
||||||
|
// IEnumerable / Iterators
|
||||||
|
Assert.Equal(Expected, en.Pow<Length, Length>(2.0).First()._Value);
|
||||||
|
Assert.Equal(Expected, enNull.Pow<Length, Length>(2.0).First(x => x.HasValue)?._Value);
|
||||||
|
|
||||||
|
// Дополнительные итераторы
|
||||||
|
Assert.Equal(Expected, en.PowIterator<Length, Length>(2.0).First()._Value);
|
||||||
|
Assert.Equal(Expected, enNull.PowNullableIterator<Length, Length>(2.0).First(x => x.HasValue)?._Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
59
QWERTYkez.Mensura.Tests/CollectionsRootOfCubeExtensions.cs
Normal file
59
QWERTYkez.Mensura.Tests/CollectionsRootOfCubeExtensions.cs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
namespace QWERTYkez.Mensura.Tests;
|
||||||
|
|
||||||
|
public class CollectionsRootOfCubeExtensions
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Cbrt_Array_CalculatesCorrectly()
|
||||||
|
{
|
||||||
|
Length[] source = [new(4), new(9), new(16), new(25)];
|
||||||
|
// Ожидаем корень, но важно: Math.Sqrt(4) = 2.
|
||||||
|
// Если ваш код делает специфичные преобразования, адаптируйте Assert.
|
||||||
|
var result = source.Cbrt<Length, Length>();
|
||||||
|
|
||||||
|
Assert.Equal(2, result[0]._Value);
|
||||||
|
Assert.Equal(3, result[1]._Value);
|
||||||
|
Assert.Equal(4, result[2]._Value);
|
||||||
|
Assert.Equal(5, result[3]._Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Cbrt_NullableArray_HandlesNulls()
|
||||||
|
{
|
||||||
|
Length?[] source = [new(16), null, new(36)];
|
||||||
|
var result = source.Cbrt<Length, Length>();
|
||||||
|
|
||||||
|
Assert.Equal(4, result[0]?._Value);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(6, result[2]?._Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Cbrt_DestinationTooShort_ThrowsArgumentException()
|
||||||
|
{
|
||||||
|
Length[] source = [new(1), new(4)];
|
||||||
|
Length[] dest = new Length[1];
|
||||||
|
|
||||||
|
Assert.Throws<ArgumentException>(() => source.Cbrt(dest));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Cbrt_List_WorksCorrectly()
|
||||||
|
{
|
||||||
|
var list = new List<Length> { new(1), new(4) };
|
||||||
|
var result = list.Cbrt<Length, Length>();
|
||||||
|
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1, result[0]._Value);
|
||||||
|
Assert.Equal(2, result[1]._Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Cbrt_IEnumerable_NoExtraAllocations()
|
||||||
|
{
|
||||||
|
IEnumerable<Length> source = new HashSet<Length> { new(9), new(81) };
|
||||||
|
var result = source.Cbrt<Length, Length>().ToList();
|
||||||
|
|
||||||
|
Assert.Contains(result, x => x._Value == 3);
|
||||||
|
Assert.Contains(result, x => x._Value == 9);
|
||||||
|
}
|
||||||
|
}
|
||||||
75
QWERTYkez.Mensura.Tests/CollectionsRootOfSquareExtensions.cs
Normal file
75
QWERTYkez.Mensura.Tests/CollectionsRootOfSquareExtensions.cs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
namespace QWERTYkez.Mensura.Tests;
|
||||||
|
|
||||||
|
public class CollectionsRootOfSquareExtensions
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Sqrt_Array_ShouldCalculateCorrectly()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
Length[] source = [new(4), new(9), new(16)];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
Length[] result = source.Sqrt<Length, Length>();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(2, result[0]._Value);
|
||||||
|
Assert.Equal(3, result[1]._Value);
|
||||||
|
Assert.Equal(4, result[2]._Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sqrt_NullableArray_ShouldHandleNulls()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
Length?[] source = [new(25), null, new(100)];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
Length?[] result = source.Sqrt<Length, Length>();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(5, result[0]?._Value);
|
||||||
|
Assert.Null(result[1]);
|
||||||
|
Assert.Equal(10, result[2]?._Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sqrt_List_ShouldReturnCorrectList()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var source = new List<Length> { new(1), new(4), new(9) };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = source.Sqrt<Length, Length>();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(3, result.Count);
|
||||||
|
Assert.Equal(1, result[0]._Value);
|
||||||
|
Assert.Equal(2, result[1]._Value);
|
||||||
|
Assert.Equal(3, result[2]._Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sqrt_DestinationTooShort_ShouldThrowArgumentException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
Length[] source = [new(4), new(9)];
|
||||||
|
Length[] dest = new Length[1]; // Слишком мало
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.Throws<ArgumentException>(() => source.AsSpan().Sqrt(dest.AsSpan()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sqrt_IEnumerable_ShouldWorkWithGenericCollection()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
IEnumerable<Length> source = new HashSet<Length> { new(16), new(64) };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = source.Sqrt<Length, Length>().ToList();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Contains(result, x => x._Value == 4);
|
||||||
|
Assert.Contains(result, x => x._Value == 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
164
QWERTYkez.Mensura.Tests/DoubleExtensions.cs
Normal file
164
QWERTYkez.Mensura.Tests/DoubleExtensions.cs
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
namespace QWERTYkez.Mensura.Tests;
|
||||||
|
|
||||||
|
public class DoubleExtensions
|
||||||
|
{
|
||||||
|
#region 1. Тесты скалярных типов (Обычные, Экзотические и Nullable)
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToDouble_Should_Convert_ExoticTypes_Without_InvalidCastException()
|
||||||
|
{
|
||||||
|
// Проверяем типы, которые раньше могли падать в рантайме из-за Convert.ToDouble(object)
|
||||||
|
Half halfValue = (Half)3.14f;
|
||||||
|
Int128 int128Value = Int128.Parse("1234567890123456789012345");
|
||||||
|
UInt128 uInt128Value = UInt128.Parse("9876543210987654321098765");
|
||||||
|
nint nintValue = 42;
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.Equal(3.14, halfValue.ToDouble(), 2);
|
||||||
|
Assert.Equal((double)int128Value, int128Value.ToDouble());
|
||||||
|
Assert.Equal((double)uInt128Value, uInt128Value.ToDouble());
|
||||||
|
Assert.Equal(42.0, nintValue.ToDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData((int)100, 100.0)]
|
||||||
|
[InlineData((byte)5, 5.0)]
|
||||||
|
[InlineData((float)1.5f, 1.5)]
|
||||||
|
public void ToDouble_StandardScalars_ShouldConvertCorrectly(object input, double expected)
|
||||||
|
{
|
||||||
|
double result = input switch
|
||||||
|
{
|
||||||
|
int i => i.ToDouble(),
|
||||||
|
byte b => b.ToDouble(),
|
||||||
|
float f => f.ToDouble(),
|
||||||
|
_ => throw new ArgumentException("Unsupported type in test")
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.Equal(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToDouble_NullableScalars_Should_Return_Zero_When_Null()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
int? nullInt = null;
|
||||||
|
Half? nullHalf = null;
|
||||||
|
Int128? nullInt128 = null;
|
||||||
|
|
||||||
|
int? validInt = 10;
|
||||||
|
Half? validHalf = (Half)2.5f;
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.Equal(0d, nullInt.ToDouble());
|
||||||
|
Assert.Equal(0d, nullHalf.ToDouble());
|
||||||
|
Assert.Equal(0d, nullInt128.ToDouble());
|
||||||
|
|
||||||
|
Assert.Equal(10d, validInt.ToDouble());
|
||||||
|
Assert.Equal(2.5d, validHalf.ToDouble(), 1);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 2. Тесты SIMD и оптимизаций коллекций (Различные длины массивов)
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(0)] // Пустой массив
|
||||||
|
[InlineData(1)] // 1 элемент (чисто скалярный fallback)
|
||||||
|
[InlineData(7)] // Нечетное число элементов
|
||||||
|
[InlineData(16)] // Кратный размер (размер Vector128/Vector256)
|
||||||
|
[InlineData(35)] // Большой массив с остатком для скалярного хвоста
|
||||||
|
public void ToDouble_ArrayAndList_Should_Correctly_Map_Via_SIMD_Or_Fallback(int count)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
float[] sourceArray = [.. Enumerable.Range(1, count).Select(x => x * 1.5f)];
|
||||||
|
List<float> sourceList = [.. sourceArray];
|
||||||
|
|
||||||
|
double[] destFromArray = new double[count];
|
||||||
|
double[] destFromList = new double[count];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
// Явное приведение к IReadOnlyCollection устраняет ошибку CS0121 (неоднозначность вызова)
|
||||||
|
((IReadOnlyCollection<float>)sourceArray).ToDouble(destFromArray);
|
||||||
|
((IReadOnlyCollection<float>)sourceList).ToDouble(destFromList);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
double expected = sourceArray[i];
|
||||||
|
Assert.Equal(expected, destFromArray[i]);
|
||||||
|
Assert.Equal(expected, destFromList[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 3. Тесты Nullable-коллекций (Проверка на null-элементы внутри)
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToDouble_Nullable_Collections_Should_Keep_Nulls_In_Destination()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
UInt128?[] sourceArray = [10, null, 20, null, 30];
|
||||||
|
double?[] destination = new double?[sourceArray.Length];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
((IReadOnlyCollection<UInt128?>)sourceArray).ToDouble(destination);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(10d, destination[0]);
|
||||||
|
Assert.Null(destination[1]);
|
||||||
|
Assert.Equal(20d, destination[2]);
|
||||||
|
Assert.Null(destination[3]);
|
||||||
|
Assert.Equal(30d, destination[4]);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 4. Тесты LINQ / Отложенного выполнения (IEnumerable)
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToDouble_IEnumerable_Extension_Should_Handle_Execution_Types_Correctly()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
int[] array = [1, 2, 3];
|
||||||
|
List<int> list = [4, 5, 6];
|
||||||
|
IEnumerable<int> genericEnum = Enumerable.Range(7, 3);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var resFromArray = array.ToDouble(); // Быстрый бранч для массива
|
||||||
|
var resFromList = list.ToDouble(); // Быстрый бранч для списка
|
||||||
|
var resFromEnum = genericEnum.ToDouble(); // Медленный итератор по IEnumerable
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal([1d, 2d, 3d], resFromArray);
|
||||||
|
Assert.Equal([4d, 5d, 6d], resFromList);
|
||||||
|
Assert.Equal([7d, 8d, 9d], resFromEnum);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 5. Тесты безопасности и валидации аргументов
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToDouble_Should_Throw_ArgumentException_When_Destination_Is_Too_Short()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
int[] source = [1, 2, 3, 4, 5];
|
||||||
|
double[] destinationTooShort = new double[4]; // Нужен размер >= 5
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.Throws<ArgumentException>(() => ((IReadOnlyCollection<int>)source).ToDouble(destinationTooShort));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToDouble_Should_Do_Nothing_And_Return_When_Collection_Is_Empty_Or_Null()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
int[]? nullArray = null;
|
||||||
|
int[] emptyArray = [];
|
||||||
|
double[] destination = new double[5];
|
||||||
|
|
||||||
|
// Act & Assert (Не должно выбрасывать NullReferenceException или ArgumentException)
|
||||||
|
((IReadOnlyCollection<int>?)nullArray)!.ToDouble(destination);
|
||||||
|
((IReadOnlyCollection<int>)emptyArray).ToDouble(destination);
|
||||||
|
|
||||||
|
Assert.All(destination, x => Assert.Equal(0d, x)); // Назначение осталось нетронутым (все нули по умолчанию)
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -7,6 +7,14 @@
|
|||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net10.0|AnyCPU'">
|
||||||
|
<NoWarn>1701;1702;IDE0221</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net10.0|AnyCPU'">
|
||||||
|
<NoWarn>1701;1702;IDE0221</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="coverlet.collector" Version="10.0.1">
|
<PackageReference Include="coverlet.collector" Version="10.0.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
@@ -23,6 +31,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\QWERTYkez.Mensura\QWERTYkez.Mensura.csproj" />
|
<ProjectReference Include="..\QWERTYkez.Mensura\QWERTYkez.Mensura.csproj" />
|
||||||
|
<InternalsVisibleTo Include="..\QWERTYkez.Mensura\QWERTYkez.Mensura.csproj" />
|
||||||
|
|
||||||
<ProjectReference Include="..\QWERTYkez.Mensura.Generator\QWERTYkez.Mensura.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
<ProjectReference Include="..\QWERTYkez.Mensura.Generator\QWERTYkez.Mensura.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
2
QWERTYkez.Mensura.Tests/globals.cs
Normal file
2
QWERTYkez.Mensura.Tests/globals.cs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
global using QWERTYkez.Mensura.Extensions;
|
||||||
|
global using QWERTYkez.Mensura.Units;
|
||||||
@@ -296,80 +296,6 @@ internal static partial class AggregateUnitExtensions
|
|||||||
return CollectionsMarshal.AsSpan(list).Min();
|
return CollectionsMarshal.AsSpan(list).Min();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static T Sum<T>(this ICollection<T> collection)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (collection == null || collection.Count == 0) return default;
|
|
||||||
if (collection is T[] array) return array.Sum();
|
|
||||||
if (collection is List<T> list) return list.Sum();
|
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(collection.Count);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
collection.CopyTo(sharedArray, 0); // Встроенный CopyTo работает быстрее, чем ручной foreach
|
|
||||||
return new ReadOnlySpan<T>(sharedArray, 0, collection.Count).Sum();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static T Avg<T>(this ICollection<T> collection)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (collection == null || collection.Count == 0) return double.NaN.ToUnit<T>();
|
|
||||||
if (collection is T[] array) return array.Avg();
|
|
||||||
if (collection is List<T> list) return list.Avg();
|
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(collection.Count);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
collection.CopyTo(sharedArray, 0);
|
|
||||||
return new ReadOnlySpan<T>(sharedArray, 0, collection.Count).Avg();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static T Max<T>(this ICollection<T> collection)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (collection == null || collection.Count == 0) return double.MinValue.ToUnit<T>();
|
|
||||||
if (collection is T[] array) return array.Max();
|
|
||||||
if (collection is List<T> list) return list.Max();
|
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(collection.Count);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
collection.CopyTo(sharedArray, 0);
|
|
||||||
return new ReadOnlySpan<T>(sharedArray, 0, collection.Count).Max();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static T Min<T>(this ICollection<T> collection)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (collection == null || collection.Count == 0) return double.MaxValue.ToUnit<T>();
|
|
||||||
if (collection is T[] array) return array.Min();
|
|
||||||
if (collection is List<T> list) return list.Min();
|
|
||||||
|
|
||||||
T[] sharedArray = ArrayPool<T>.Shared.Rent(collection.Count);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
collection.CopyTo(sharedArray, 0);
|
|
||||||
return new ReadOnlySpan<T>(sharedArray, 0, collection.Count).Min();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static T Sum<T>(this IReadOnlyCollection<T> collection)
|
internal static T Sum<T>(this IReadOnlyCollection<T> collection)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -446,7 +372,6 @@ internal static partial class AggregateUnitExtensions
|
|||||||
// Быстрый SIMD-путь для готовых коллекций (0 аллокаций)
|
// Быстрый SIMD-путь для готовых коллекций (0 аллокаций)
|
||||||
if (collection is T[] array) return array.Sum();
|
if (collection is T[] array) return array.Sum();
|
||||||
if (collection is List<T> list) return list.Sum();
|
if (collection is List<T> list) return list.Sum();
|
||||||
if (collection is ICollection<T> col) return col.Sum();
|
|
||||||
if (collection is IReadOnlyCollection<T> roc) return roc.Sum();
|
if (collection is IReadOnlyCollection<T> roc) return roc.Sum();
|
||||||
|
|
||||||
// Медленный путь для yield return: считаем на лету без буферов
|
// Медленный путь для yield return: считаем на лету без буферов
|
||||||
@@ -468,7 +393,6 @@ internal static partial class AggregateUnitExtensions
|
|||||||
|
|
||||||
if (collection is T[] array) return array.Avg();
|
if (collection is T[] array) return array.Avg();
|
||||||
if (collection is List<T> list) return list.Avg();
|
if (collection is List<T> list) return list.Avg();
|
||||||
if (collection is ICollection<T> col) return col.Avg();
|
|
||||||
if (collection is IReadOnlyCollection<T> roc) return roc.Avg();
|
if (collection is IReadOnlyCollection<T> roc) return roc.Avg();
|
||||||
|
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
@@ -492,7 +416,6 @@ internal static partial class AggregateUnitExtensions
|
|||||||
|
|
||||||
if (collection is T[] array) return array.Max();
|
if (collection is T[] array) return array.Max();
|
||||||
if (collection is List<T> list) return list.Max();
|
if (collection is List<T> list) return list.Max();
|
||||||
if (collection is ICollection<T> col) return col.Max();
|
|
||||||
if (collection is IReadOnlyCollection<T> roc) return roc.Max();
|
if (collection is IReadOnlyCollection<T> roc) return roc.Max();
|
||||||
|
|
||||||
double max = double.MinValue;
|
double max = double.MinValue;
|
||||||
@@ -514,7 +437,6 @@ internal static partial class AggregateUnitExtensions
|
|||||||
|
|
||||||
if (collection is T[] array) return array.Min();
|
if (collection is T[] array) return array.Min();
|
||||||
if (collection is List<T> list) return list.Min();
|
if (collection is List<T> list) return list.Min();
|
||||||
if (collection is ICollection<T> col) return col.Min();
|
|
||||||
if (collection is IReadOnlyCollection<T> roc) return roc.Min();
|
if (collection is IReadOnlyCollection<T> roc) return roc.Min();
|
||||||
|
|
||||||
double min = double.MaxValue;
|
double min = double.MaxValue;
|
||||||
@@ -708,80 +630,6 @@ internal static partial class AggregateUnitExtensions
|
|||||||
return CollectionsMarshal.AsSpan(list).Min();
|
return CollectionsMarshal.AsSpan(list).Min();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static T Sum<T>(this ICollection<T?> collection)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (collection == null || collection.Count == 0) return default;
|
|
||||||
if (collection is T?[] array) return array.Sum();
|
|
||||||
if (collection is List<T?> list) return list.Sum();
|
|
||||||
|
|
||||||
T?[] sharedArray = ArrayPool<T?>.Shared.Rent(collection.Count);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
collection.CopyTo(sharedArray, 0);
|
|
||||||
return new ReadOnlySpan<T?>(sharedArray, 0, collection.Count).Sum();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static T Avg<T>(this ICollection<T?> collection)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (collection == null || collection.Count == 0) return double.NaN.ToUnit<T>();
|
|
||||||
if (collection is T?[] array) return array.Avg();
|
|
||||||
if (collection is List<T?> list) return list.Avg();
|
|
||||||
|
|
||||||
T?[] sharedArray = ArrayPool<T?>.Shared.Rent(collection.Count);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
collection.CopyTo(sharedArray, 0);
|
|
||||||
return new ReadOnlySpan<T?>(sharedArray, 0, collection.Count).Avg();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static T Max<T>(this ICollection<T?> collection)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (collection == null || collection.Count == 0) return double.MinValue.ToUnit<T>();
|
|
||||||
if (collection is T?[] array) return array.Max();
|
|
||||||
if (collection is List<T?> list) return list.Max();
|
|
||||||
|
|
||||||
T?[] sharedArray = ArrayPool<T?>.Shared.Rent(collection.Count);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
collection.CopyTo(sharedArray, 0);
|
|
||||||
return new ReadOnlySpan<T?>(sharedArray, 0, collection.Count).Max();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static T Min<T>(this ICollection<T?> collection)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (collection == null || collection.Count == 0) return double.MaxValue.ToUnit<T>();
|
|
||||||
if (collection is T?[] array) return array.Min();
|
|
||||||
if (collection is List<T?> list) return list.Min();
|
|
||||||
|
|
||||||
T?[] sharedArray = ArrayPool<T?>.Shared.Rent(collection.Count);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
collection.CopyTo(sharedArray, 0);
|
|
||||||
return new ReadOnlySpan<T?>(sharedArray, 0, collection.Count).Min();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<T?>.Shared.Return(sharedArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static T Sum<T>(this IReadOnlyCollection<T?> collection)
|
internal static T Sum<T>(this IReadOnlyCollection<T?> collection)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -857,7 +705,6 @@ internal static partial class AggregateUnitExtensions
|
|||||||
// Быстрый SIMD-путь для готовых коллекций за 0 аллокаций
|
// Быстрый SIMD-путь для готовых коллекций за 0 аллокаций
|
||||||
if (collection is T?[] array) return array.Sum();
|
if (collection is T?[] array) return array.Sum();
|
||||||
if (collection is List<T?> list) return list.Sum();
|
if (collection is List<T?> list) return list.Sum();
|
||||||
if (collection is ICollection<T?> col) return col.Sum();
|
|
||||||
if (collection is IReadOnlyCollection<T?> roc) return roc.Sum();
|
if (collection is IReadOnlyCollection<T?> roc) return roc.Sum();
|
||||||
|
|
||||||
// Медленный путь для ленивого yield return: вычисляем на лету
|
// Медленный путь для ленивого yield return: вычисляем на лету
|
||||||
@@ -882,7 +729,6 @@ internal static partial class AggregateUnitExtensions
|
|||||||
|
|
||||||
if (collection is T?[] array) return array.Avg();
|
if (collection is T?[] array) return array.Avg();
|
||||||
if (collection is List<T?> list) return list.Avg();
|
if (collection is List<T?> list) return list.Avg();
|
||||||
if (collection is ICollection<T?> col) return col.Avg();
|
|
||||||
if (collection is IReadOnlyCollection<T?> roc) return roc.Avg();
|
if (collection is IReadOnlyCollection<T?> roc) return roc.Avg();
|
||||||
|
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
@@ -909,7 +755,6 @@ internal static partial class AggregateUnitExtensions
|
|||||||
|
|
||||||
if (collection is T?[] array) return array.Max();
|
if (collection is T?[] array) return array.Max();
|
||||||
if (collection is List<T?> list) return list.Max();
|
if (collection is List<T?> list) return list.Max();
|
||||||
if (collection is ICollection<T?> col) return col.Max();
|
|
||||||
if (collection is IReadOnlyCollection<T?> roc) return roc.Max();
|
if (collection is IReadOnlyCollection<T?> roc) return roc.Max();
|
||||||
|
|
||||||
double max = double.MinValue;
|
double max = double.MinValue;
|
||||||
@@ -934,7 +779,6 @@ internal static partial class AggregateUnitExtensions
|
|||||||
|
|
||||||
if (collection is T?[] array) return array.Min();
|
if (collection is T?[] array) return array.Min();
|
||||||
if (collection is List<T?> list) return list.Min();
|
if (collection is List<T?> list) return list.Min();
|
||||||
if (collection is ICollection<T?> col) return col.Min();
|
|
||||||
if (collection is IReadOnlyCollection<T?> roc) return roc.Min();
|
if (collection is IReadOnlyCollection<T?> roc) return roc.Min();
|
||||||
|
|
||||||
double min = double.MaxValue;
|
double min = double.MaxValue;
|
||||||
|
|||||||
@@ -1,51 +1,35 @@
|
|||||||
namespace QWERTYkez.Mensura.Extensions;
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
|
namespace QWERTYkez.Mensura.Extensions;
|
||||||
|
|
||||||
internal static partial class CastExtensions
|
internal static partial class CastExtensions
|
||||||
{
|
{
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static double ToDouble<T>(this T unit)
|
internal static double ToDouble<T>(this T unit) where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
=> Unsafe.As<T, double>(ref unit);
|
||||||
{
|
|
||||||
return Unsafe.As<T, double>(ref unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static T ToUnit<T>(this double val)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
return Unsafe.As<double, T>(ref val);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static void SetCountUnsafe<T>(this List<T> list, int count)
|
|
||||||
{
|
|
||||||
// Берем адрес управляемого объекта List в памяти
|
|
||||||
// Объект передается по ref-ссылке, преобразуется в указатель
|
|
||||||
ref var mimic = ref Unsafe.As<List<T>, Mimics<T>>(ref list);
|
|
||||||
|
|
||||||
// Меняем приватный размер напрямую в памяти объекта!
|
|
||||||
mimic.Size = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static T ToUnit<T>(this double val)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T> => Unsafe.As<double, T>(ref val);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static List<R> WrapAsList<T, R>(this T[] array)
|
internal static List<R> WrapAsList<T, R>(this T[] array)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
// Создаём пустой список с нулевой ёмкостью
|
if (array is null) return null!;
|
||||||
|
|
||||||
|
// 1. Физически меняем паспорт (MethodTable) массива на целевой тип R[]
|
||||||
|
object arrObj = array;
|
||||||
|
unsafe { *(nint*)*(nint*)Unsafe.AsPointer(ref arrObj) = typeof(R[]).TypeHandle.Value; }
|
||||||
|
R[] morphedArray = Unsafe.As<R[]>(arrObj);
|
||||||
|
|
||||||
|
// 2. Вшиваем его в новый список
|
||||||
var list = new List<R>(0);
|
var list = new List<R>(0);
|
||||||
|
ref var mimic = ref Unsafe.As<List<R>, ListMimic<R>>(ref list);
|
||||||
// Получаем внутреннюю структуру списка
|
mimic.Items = morphedArray;
|
||||||
ref var mimic = ref Unsafe.As<List<R>, Mimics<T>>(ref list);
|
|
||||||
|
|
||||||
// Подменяем массив и устанавливаем размер
|
|
||||||
mimic.Items = array;
|
|
||||||
mimic.Size = array.Length;
|
mimic.Size = array.Length;
|
||||||
mimic.Version = 1; // любое ненулевое значение для консистенции
|
mimic.Version = 1;
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -55,16 +39,17 @@ internal static partial class CastExtensions
|
|||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
// Создаём пустой список с нулевой ёмкостью
|
if (array is null) return null!;
|
||||||
|
|
||||||
|
object arrObj = array;
|
||||||
|
unsafe { *(nint*)*(nint*)Unsafe.AsPointer(ref arrObj) = typeof(R?[]).TypeHandle.Value; }
|
||||||
|
R?[] morphedArray = Unsafe.As<R?[]>(arrObj);
|
||||||
|
|
||||||
var list = new List<R?>(0);
|
var list = new List<R?>(0);
|
||||||
|
ref var mimic = ref Unsafe.As<List<R?>, ListMimic<R?>>(ref list);
|
||||||
// Получаем внутреннюю структуру списка
|
mimic.Items = morphedArray;
|
||||||
ref var mimic = ref Unsafe.As<List<R?>, Mimics<T?>>(ref list);
|
|
||||||
|
|
||||||
// Подменяем массив и устанавливаем размер
|
|
||||||
mimic.Items = array;
|
|
||||||
mimic.Size = array.Length;
|
mimic.Size = array.Length;
|
||||||
mimic.Version = 1; // любое ненулевое значение для консистенции
|
mimic.Version = 1;
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -73,16 +58,17 @@ internal static partial class CastExtensions
|
|||||||
internal static List<double> WrapAsList<T>(this T[] array)
|
internal static List<double> WrapAsList<T>(this T[] array)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
// Создаём пустой список с нулевой ёмкостью
|
if (array is null) return null!;
|
||||||
|
|
||||||
|
object arrObj = array;
|
||||||
|
unsafe { *(nint*)*(nint*)Unsafe.AsPointer(ref arrObj) = typeof(double[]).TypeHandle.Value; }
|
||||||
|
double[] morphedArray = Unsafe.As<double[]>(arrObj);
|
||||||
|
|
||||||
var list = new List<double>(0);
|
var list = new List<double>(0);
|
||||||
|
ref var mimic = ref Unsafe.As<List<double>, ListMimic<double>>(ref list);
|
||||||
// Получаем внутреннюю структуру списка
|
mimic.Items = morphedArray;
|
||||||
ref var mimic = ref Unsafe.As<List<double>, Mimics<T>>(ref list);
|
|
||||||
|
|
||||||
// Подменяем массив и устанавливаем размер
|
|
||||||
mimic.Items = array;
|
|
||||||
mimic.Size = array.Length;
|
mimic.Size = array.Length;
|
||||||
mimic.Version = 1; // любое ненулевое значение для консистенции
|
mimic.Version = 1;
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -91,16 +77,17 @@ internal static partial class CastExtensions
|
|||||||
internal static List<double?> WrapAsList<T>(this T?[] array)
|
internal static List<double?> WrapAsList<T>(this T?[] array)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
// Создаём пустой список с нулевой ёмкостью
|
if (array is null) return null!;
|
||||||
|
|
||||||
|
object arrObj = array;
|
||||||
|
unsafe { *(nint*)*(nint*)Unsafe.AsPointer(ref arrObj) = typeof(double?[]).TypeHandle.Value; }
|
||||||
|
double?[] morphedArray = Unsafe.As<double?[]>(arrObj);
|
||||||
|
|
||||||
var list = new List<double?>(0);
|
var list = new List<double?>(0);
|
||||||
|
ref var mimic = ref Unsafe.As<List<double?>, ListMimic<double?>>(ref list);
|
||||||
// Получаем внутреннюю структуру списка
|
mimic.Items = morphedArray;
|
||||||
ref var mimic = ref Unsafe.As<List<double?>, Mimics<T?>>(ref list);
|
|
||||||
|
|
||||||
// Подменяем массив и устанавливаем размер
|
|
||||||
mimic.Items = array;
|
|
||||||
mimic.Size = array.Length;
|
mimic.Size = array.Length;
|
||||||
mimic.Version = 1; // любое ненулевое значение для консистенции
|
mimic.Version = 1;
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -108,16 +95,14 @@ internal static partial class CastExtensions
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static List<double> WrapAsList(this double[] array)
|
internal static List<double> WrapAsList(this double[] array)
|
||||||
{
|
{
|
||||||
// Создаём пустой список с нулевой ёмкостью
|
if (array is null) return null!;
|
||||||
|
|
||||||
|
// Массив уже имеет тип double[], подмена MethodTable не требуется
|
||||||
var list = new List<double>(0);
|
var list = new List<double>(0);
|
||||||
|
ref var mimic = ref Unsafe.As<List<double>, ListMimic<double>>(ref list);
|
||||||
// Получаем внутреннюю структуру списка
|
|
||||||
ref var mimic = ref Unsafe.As<List<double>, Mimics<double>>(ref list);
|
|
||||||
|
|
||||||
// Подменяем массив и устанавливаем размер
|
|
||||||
mimic.Items = array;
|
mimic.Items = array;
|
||||||
mimic.Size = array.Length;
|
mimic.Size = array.Length;
|
||||||
mimic.Version = 1; // любое ненулевое значение для консистенции
|
mimic.Version = 1;
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -125,28 +110,75 @@ internal static partial class CastExtensions
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static List<double?> WrapAsList(this double?[] array)
|
internal static List<double?> WrapAsList(this double?[] array)
|
||||||
{
|
{
|
||||||
// Создаём пустой список с нулевой ёмкостью
|
if (array is null) return null!;
|
||||||
|
|
||||||
|
// Массив уже имеет тип double?[], подмена MethodTable не требуется
|
||||||
var list = new List<double?>(0);
|
var list = new List<double?>(0);
|
||||||
|
ref var mimic = ref Unsafe.As<List<double?>, ListMimic<double?>>(ref list);
|
||||||
// Получаем внутреннюю структуру списка
|
|
||||||
ref var mimic = ref Unsafe.As<List<double?>, Mimics<double?>>(ref list);
|
|
||||||
|
|
||||||
// Подменяем массив и устанавливаем размер
|
|
||||||
mimic.Items = array;
|
mimic.Items = array;
|
||||||
mimic.Size = array.Length;
|
mimic.Size = array.Length;
|
||||||
mimic.Version = 1; // любое ненулевое значение для консистенции
|
mimic.Version = 1;
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region Инфраструктура Нативного Доступа (Zero-Overhead)
|
||||||
|
|
||||||
|
// Генератор сверхбыстрого доступа к приватным полям List<T> через чистый IL.
|
||||||
|
// Работает со скоростью обычного обращения к полю (компилируется в смещение указателя).
|
||||||
|
private static class ListAccessor<T>
|
||||||
|
{
|
||||||
|
public delegate ref T[] GetItemsRefDelegate(List<T> list);
|
||||||
|
public static readonly GetItemsRefDelegate GetItemsRef;
|
||||||
|
|
||||||
|
static ListAccessor()
|
||||||
|
{
|
||||||
|
var field = typeof(List<T>).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||||
|
?? throw new InvalidOperationException("CLR Layout changed: _items field not found.");
|
||||||
|
|
||||||
|
var dm = new DynamicMethod("GetItemsRef", typeof(T[]).MakeByRefType(), [typeof(List<T>)], typeof(ListAccessor<T>).Module, true);
|
||||||
|
var il = dm.GetILGenerator();
|
||||||
|
il.Emit(OpCodes.Ldarg_0); // Загружаем ссылку на List<T>
|
||||||
|
il.Emit(OpCodes.Ldflda, field); // Получаем управляемый указатель (ref) на поле _items
|
||||||
|
il.Emit(OpCodes.Ret); // Возвращаем его
|
||||||
|
|
||||||
|
GetItemsRef = dm.CreateDelegate<GetItemsRefDelegate>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Реализация ReCast со сменой MethodTable (In-Place Object Morphing)
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static List<R> ReCast<T, R>(this List<T> list)
|
internal static List<R> ReCast<T, R>(this List<T> list)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
return Unsafe.As<List<T>, List<R>>(ref list);
|
if (list is null) return null!;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
// 1. Морфим внутренний массив со скоростью мысли
|
||||||
|
T[] items = ListAccessor<T>.GetItemsRef(list);
|
||||||
|
if (items is not null)
|
||||||
|
{
|
||||||
|
object itemsObj = items;
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref itemsObj) = typeof(R[]).TypeHandle.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Морфим сам заголовок List
|
||||||
|
object listObj = list;
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref listObj) = typeof(List<R>).TypeHandle.Value;
|
||||||
|
|
||||||
|
return Unsafe.As<List<R>>(listObj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -154,21 +186,63 @@ internal static partial class CastExtensions
|
|||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
return Unsafe.As<List<T?>, List<R?>>(ref list);
|
if (list is null) return null!;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
T?[] items = ListAccessor<T?>.GetItemsRef(list);
|
||||||
|
if (items is not null)
|
||||||
|
{
|
||||||
|
object itemsObj = items;
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref itemsObj) = typeof(R?[]).TypeHandle.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
object listObj = list;
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref listObj) = typeof(List<R?>).TypeHandle.Value;
|
||||||
|
|
||||||
|
return Unsafe.As<List<R?>>(listObj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static List<double> ReCast<T>(this List<T> list)
|
internal static List<double> ReCast<T>(this List<T> list)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
return Unsafe.As<List<T>, List<double>>(ref list);
|
if (list is null) return null!;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
T[] items = ListAccessor<T>.GetItemsRef(list);
|
||||||
|
if (items is not null)
|
||||||
|
{
|
||||||
|
object itemsObj = items;
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref itemsObj) = typeof(double[]).TypeHandle.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
object listObj = list;
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref listObj) = typeof(List<double>).TypeHandle.Value;
|
||||||
|
|
||||||
|
return Unsafe.As<List<double>>(listObj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static List<double?> ReCast<T>(this List<T?> list)
|
internal static List<double?> ReCast<T>(this List<T?> list)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
return Unsafe.As<List<T?>, List<double?>>(ref list);
|
if (list is null) return null!;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
T?[] items = ListAccessor<T?>.GetItemsRef(list);
|
||||||
|
if (items is not null)
|
||||||
|
{
|
||||||
|
object itemsObj = items;
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref itemsObj) = typeof(double?[]).TypeHandle.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
object listObj = list;
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref listObj) = typeof(List<double?>).TypeHandle.Value;
|
||||||
|
|
||||||
|
return Unsafe.As<List<double?>>(listObj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -176,7 +250,14 @@ internal static partial class CastExtensions
|
|||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
return Unsafe.As<T[], R[]>(ref array);
|
if (array is null) return null!;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
object obj = array;
|
||||||
|
// Ужатие магии: берем адрес переменной на стеке -> читаем адрес объекта в куче -> пишем туда новый MethodTable
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref obj) = typeof(R[]).TypeHandle.Value;
|
||||||
|
return Unsafe.As<R[]>(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -184,34 +265,66 @@ internal static partial class CastExtensions
|
|||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
return Unsafe.As<T?[], R?[]>(ref array);
|
if (array is null) return null!;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
object obj = array;
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref obj) = typeof(R?[]).TypeHandle.Value;
|
||||||
|
return Unsafe.As<R?[]>(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static double[] ReCast<T>(this T[] array)
|
internal static double[] ReCast<T>(this T[] array)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
return Unsafe.As<T[], double[]>(ref array);
|
if (array is null) return null!;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
object obj = array;
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref obj) = typeof(double[]).TypeHandle.Value;
|
||||||
|
return Unsafe.As<double[]>(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static double?[] ReCast<T>(this T?[] array)
|
internal static double?[] ReCast<T>(this T?[] array)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
{
|
{
|
||||||
return Unsafe.As<T?[], double?[]>(ref array);
|
if (array is null) return null!;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
object obj = array;
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref obj) = typeof(double?[]).TypeHandle.Value;
|
||||||
|
return Unsafe.As<double?[]>(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static R[] ReCast<R>(this double[] array)
|
internal static R[] ReCast<R>(this double[] array)
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
return Unsafe.As<double[], R[]>(ref array);
|
if (array is null) return null!;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
object obj = array;
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref obj) = typeof(R[]).TypeHandle.Value;
|
||||||
|
return Unsafe.As<R[]>(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static R?[] ReCast<R>(this double?[] array)
|
internal static R?[] ReCast<R>(this double?[] array)
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
return Unsafe.As<double?[], R?[]>(ref array);
|
if (array is null) return null!;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
object obj = array;
|
||||||
|
*(nint*)*(nint*)Unsafe.AsPointer(ref obj) = typeof(R?[]).TypeHandle.Value;
|
||||||
|
return Unsafe.As<R?[]>(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -264,80 +264,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
return resultArray.WrapAsList<R, R>();
|
return resultArray.WrapAsList<R, R>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static void Div<T, R>(this ICollection<T> units, double divisor, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { DivideCore(array, divisor, count, destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).DivideCore(divisor, count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
double invDivisor = 1.0 / divisor;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (item.ToDouble() * invDivisor).ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static void Div<T, R>(this ICollection<T?> units, double divisor, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.DivideCore(divisor, count, destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).DivideCore(divisor, count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
double invDivisor = 1.0 / divisor;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (item.Value.ToDouble() * invDivisor).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
internal static void Div<T, R>(this double dividend, ICollection<T> units, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { dividend.DivideCore(array, count, destination); return; }
|
|
||||||
if (units is List<T> list) { dividend.DivideCore(CollectionsMarshal.AsSpan(list), count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (dividend / item.ToDouble()).ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static void Div<T, R>(this double dividend, ICollection<T?> units, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { dividend.DivideCore(array, count, destination); return; }
|
|
||||||
if (units is List<T?> list) { dividend.DivideCore(CollectionsMarshal.AsSpan(list), count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (dividend / item.Value.ToDouble()).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static void Div<T, R>(this IReadOnlyCollection<T> units, double divisor, Span<R> destination)
|
internal static void Div<T, R>(this IReadOnlyCollection<T> units, double divisor, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -454,12 +380,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Div<T, R>(divisor);
|
if (units is T[] array) return array.Div<T, R>(divisor);
|
||||||
if (units is List<T> list) return list.Div<T, R>(divisor);
|
if (units is List<T> list) return list.Div<T, R>(divisor);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Div(divisor, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -475,12 +395,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Div<T, R>(divisor);
|
if (units is T?[] array) return array.Div<T, R>(divisor);
|
||||||
if (units is List<T?> list) return list.Div<T, R>(divisor);
|
if (units is List<T?> list) return list.Div<T, R>(divisor);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Div(divisor, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -496,12 +410,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return dividend.Div<T, R>(array);
|
if (units is T[] array) return dividend.Div<T, R>(array);
|
||||||
if (units is List<T> list) return dividend.Div<T, R>(list);
|
if (units is List<T> list) return dividend.Div<T, R>(list);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
dividend.Div(arr, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -517,12 +425,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return dividend.Div<T, R>(array);
|
if (units is T?[] array) return dividend.Div<T, R>(array);
|
||||||
if (units is List<T?> list) return dividend.Div<T, R>(list);
|
if (units is List<T?> list) return dividend.Div<T, R>(list);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
dividend.Div(arr, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -670,76 +572,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
return resultArray.WrapAsList<T, T>();
|
return resultArray.WrapAsList<T, T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static void Div<T>(this ICollection<T> units, double divisor, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { array.Div(divisor, destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
double invDivisor = 1.0 / divisor;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (item.ToDouble() * invDivisor).ToUnit<T>();
|
|
||||||
}
|
|
||||||
internal static void Div<T>(this ICollection<T?> units, double divisor, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.Div(divisor, destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
double invDivisor = 1.0 / divisor;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (item.Value.ToDouble() * invDivisor).ToUnit<T>() : null;
|
|
||||||
}
|
|
||||||
internal static void Div<T>(this double dividend, ICollection<T> units, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { dividend.Div(array, destination); return; }
|
|
||||||
if (units is List<T> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (dividend / item.ToDouble()).ToUnit<T>();
|
|
||||||
}
|
|
||||||
internal static void Div<T>(this double dividend, ICollection<T?> units, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { dividend.Div(array, destination); return; }
|
|
||||||
if (units is List<T?> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (dividend / item.Value.ToDouble()).ToUnit<T>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static void Div<T>(this IReadOnlyCollection<T> units, double divisor, Span<T> destination)
|
internal static void Div<T>(this IReadOnlyCollection<T> units, double divisor, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -847,12 +679,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Div(divisor);
|
if (units is T[] array) return array.Div(divisor);
|
||||||
if (units is List<T> list) return list.Div(divisor);
|
if (units is List<T> list) return list.Div(divisor);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Div(divisor, arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -867,12 +693,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Div(divisor);
|
if (units is T?[] array) return array.Div(divisor);
|
||||||
if (units is List<T?> list) return list.Div(divisor);
|
if (units is List<T?> list) return list.Div(divisor);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Div(divisor, arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -887,12 +707,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return dividend.Div(array);
|
if (units is T[] array) return dividend.Div(array);
|
||||||
if (units is List<T> list) return dividend.Div(list);
|
if (units is List<T> list) return dividend.Div(list);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
dividend.Div(arr, arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -907,12 +721,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return dividend.Div(array);
|
if (units is T?[] array) return dividend.Div(array);
|
||||||
if (units is List<T?> list) return dividend.Div(list);
|
if (units is List<T?> list) return dividend.Div(list);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
dividend.Div(arr, arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -1365,76 +1173,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
return resultArray.WrapAsList<T, T>();
|
return resultArray.WrapAsList<T, T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static void Div<T>(this ICollection<double> units, T divisor, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is double[] array) { array.Div(divisor, destination); return; }
|
|
||||||
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
double invDivisor = 1.0 / divisor.ToDouble();
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (item * invDivisor).ToUnit<T>();
|
|
||||||
}
|
|
||||||
internal static void Div<T>(this ICollection<double?> units, T divisor, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is double?[] array) { array.Div(divisor, destination); return; }
|
|
||||||
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
double invDivisor = 1.0 / divisor.ToDouble();
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (item.Value * invDivisor).ToUnit<T>() : null;
|
|
||||||
}
|
|
||||||
internal static void Div<T>(this T dividend, ICollection<double> units, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is double[] array) { dividend.Div(array, destination); return; }
|
|
||||||
if (units is List<double> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (dividend.ToDouble() / item).ToUnit<T>();
|
|
||||||
}
|
|
||||||
internal static void Div<T>(this T dividend, ICollection<double?> units, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is double?[] array) { dividend.Div(array, destination); return; }
|
|
||||||
if (units is List<double?> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (dividend.ToDouble() / item.Value).ToUnit<T>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static void Div<T>(this IReadOnlyCollection<double> units, T divisor, Span<T> destination)
|
internal static void Div<T>(this IReadOnlyCollection<double> units, T divisor, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -1542,12 +1280,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is double[] array) return array.Div(divisor);
|
if (units is double[] array) return array.Div(divisor);
|
||||||
if (units is List<double> list) return list.Div(divisor);
|
if (units is List<double> list) return list.Div(divisor);
|
||||||
if (units is ICollection<double> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.DivCore(divisor.ToDouble(), arr.Length, arr);
|
|
||||||
return arr.ReCast<T>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<double> roc)
|
if (units is IReadOnlyCollection<double> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -1562,12 +1294,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is double?[] array) return array.Div(divisor);
|
if (units is double?[] array) return array.Div(divisor);
|
||||||
if (units is List<double?> list) return list.Div(divisor);
|
if (units is List<double?> list) return list.Div(divisor);
|
||||||
if (units is ICollection<double?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.DivCore(divisor.ToDouble(), arr.Length, arr);
|
|
||||||
return arr.ReCast<T>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<double?> roc)
|
if (units is IReadOnlyCollection<double?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -1582,12 +1308,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is double[] array) return dividend.Div(array);
|
if (units is double[] array) return dividend.Div(array);
|
||||||
if (units is List<double> list) return dividend.Div(list);
|
if (units is List<double> list) return dividend.Div(list);
|
||||||
if (units is ICollection<double> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
dividend.ToDouble().DivCore(arr, arr.Length, arr);
|
|
||||||
return arr.ReCast<T>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<double> roc)
|
if (units is IReadOnlyCollection<double> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -1602,12 +1322,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is double?[] array) return dividend.Div(array);
|
if (units is double?[] array) return dividend.Div(array);
|
||||||
if (units is List<double?> list) return dividend.Div(list);
|
if (units is List<double?> list) return dividend.Div(list);
|
||||||
if (units is ICollection<double?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
dividend.ToDouble().DivCore(arr, arr.Length, arr);
|
|
||||||
return arr.ReCast<T>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<double?> roc)
|
if (units is IReadOnlyCollection<double?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -1915,76 +1629,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
return resultArray.WrapAsList();
|
return resultArray.WrapAsList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static void Div<T>(this ICollection<T> units, T divisor, Span<double> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { array.Div(divisor, destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
double invDivisor = 1.0 / divisor.ToDouble();
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.ToDouble() * invDivisor;
|
|
||||||
}
|
|
||||||
internal static void Div<T>(this ICollection<T?> units, T divisor, Span<double?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.Div(divisor, destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Div(divisor, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
double invDivisor = 1.0 / divisor.ToDouble();
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue ? item.Value.ToDouble() * invDivisor : null;
|
|
||||||
}
|
|
||||||
internal static void Div<T>(this T dividend, ICollection<T> units, Span<double> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { dividend.Div(array, destination); return; }
|
|
||||||
if (units is List<T> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
var div = dividend.ToDouble();
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = div / item.ToDouble();
|
|
||||||
}
|
|
||||||
internal static void Div<T>(this T dividend, ICollection<T?> units, Span<double?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { dividend.Div(array, destination); return; }
|
|
||||||
if (units is List<T?> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
var div = dividend.ToDouble();
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue ? div / item.Value.ToDouble() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static void Div<T>(this IReadOnlyCollection<T> units, T divisor, Span<double> destination)
|
internal static void Div<T>(this IReadOnlyCollection<T> units, T divisor, Span<double> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -2092,12 +1736,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Div(divisor);
|
if (units is T[] array) return array.Div(divisor);
|
||||||
if (units is List<T> list) return list.Div(divisor);
|
if (units is List<T> list) return list.Div(divisor);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.DivideCore(divisor.ToDouble(), arr.Length, arr);
|
|
||||||
return arr.ReCast();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -2112,12 +1750,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Div(divisor);
|
if (units is T?[] array) return array.Div(divisor);
|
||||||
if (units is List<T?> list) return list.Div(divisor);
|
if (units is List<T?> list) return list.Div(divisor);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.DivideCore(divisor.ToDouble(), arr.Length, arr);
|
|
||||||
return arr.ReCast();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -2132,12 +1764,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return dividend.Div(array);
|
if (units is T[] array) return dividend.Div(array);
|
||||||
if (units is List<T> list) return dividend.Div(list);
|
if (units is List<T> list) return dividend.Div(list);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
dividend.ToDouble().DivideCore(arr, arr.Length, arr);
|
|
||||||
return arr.ReCast();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -2152,12 +1778,6 @@ internal static partial class CollectionsDivideExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return dividend.Div(array);
|
if (units is T?[] array) return dividend.Div(array);
|
||||||
if (units is List<T?> list) return dividend.Div(list);
|
if (units is List<T?> list) return dividend.Div(list);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
dividend.ToDouble().DivideCore(arr, arr.Length, arr);
|
|
||||||
return arr.ReCast();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
|
|||||||
@@ -259,78 +259,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
return resultArray.WrapAsList<R, R>();
|
return resultArray.WrapAsList<R, R>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static void Minus<T, R>(this ICollection<T> units, double subtrahend, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { array.MinusCore(subtrahend, count, destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).MinusCore(subtrahend, count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (item.ToDouble() - subtrahend).ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static void Minus<T, R>(this ICollection<T?> units, double subtrahend, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.MinusCore(subtrahend, count, destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).MinusCore(subtrahend, count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (item.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
internal static void Minus<T, R>(this double minuend, ICollection<T> units, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { minuend.MinusCore(array, count, destination); return; }
|
|
||||||
if (units is List<T> list) { minuend.MinusCore(CollectionsMarshal.AsSpan(list), count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (minuend - item.ToDouble()).ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static void Minus<T, R>(this double minuend, ICollection<T?> units, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { minuend.MinusCore(array, count, destination); return; }
|
|
||||||
if (units is List<T?> list) { minuend.MinusCore(CollectionsMarshal.AsSpan(list), count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (minuend - item.Value.ToDouble()).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static void Minus<T, R>(this IReadOnlyCollection<T> units, double subtrahend, Span<R> destination)
|
internal static void Minus<T, R>(this IReadOnlyCollection<T> units, double subtrahend, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -443,12 +371,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Minus<T, R>(subtrahend);
|
if (units is T[] array) return array.Minus<T, R>(subtrahend);
|
||||||
if (units is List<T> list) return list.Minus<T, R>(subtrahend);
|
if (units is List<T> list) return list.Minus<T, R>(subtrahend);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Minus(subtrahend, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -464,12 +386,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Minus<T, R>(subtrahend);
|
if (units is T?[] array) return array.Minus<T, R>(subtrahend);
|
||||||
if (units is List<T?> list) return list.Minus<T, R>(subtrahend);
|
if (units is List<T?> list) return list.Minus<T, R>(subtrahend);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Minus(subtrahend, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -485,12 +401,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return minuend.Minus<T, R>(array);
|
if (units is T[] array) return minuend.Minus<T, R>(array);
|
||||||
if (units is List<T> list) return minuend.Minus<T, R>(list);
|
if (units is List<T> list) return minuend.Minus<T, R>(list);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
minuend.Minus(arr, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -506,12 +416,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return minuend.Minus<T, R>(array);
|
if (units is T?[] array) return minuend.Minus<T, R>(array);
|
||||||
if (units is List<T?> list) return minuend.Minus<T, R>(list);
|
if (units is List<T?> list) return minuend.Minus<T, R>(list);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
minuend.Minus(arr, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -660,74 +564,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
return resultArray.WrapAsList<T, T>();
|
return resultArray.WrapAsList<T, T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static void Minus<T>(this ICollection<T> units, double subtrahend, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { array.Minus(subtrahend, destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Minus(subtrahend, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (item.ToDouble() - subtrahend).ToUnit<T>();
|
|
||||||
}
|
|
||||||
internal static void Minus<T>(this ICollection<T?> units, double subtrahend, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.Minus(subtrahend, destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Minus(subtrahend, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (item.Value.ToDouble() - subtrahend).ToUnit<T>() : null;
|
|
||||||
}
|
|
||||||
internal static void Minus<T>(this double minuend, ICollection<T> units, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { minuend.Minus(array, destination); return; }
|
|
||||||
if (units is List<T> list) { minuend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (minuend - item.ToDouble()).ToUnit<T>();
|
|
||||||
}
|
|
||||||
internal static void Minus<T>(this double minuend, ICollection<T?> units, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { minuend.Minus(array, destination); return; }
|
|
||||||
if (units is List<T?> list) { minuend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (minuend - item.Value.ToDouble()).ToUnit<T>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static void Minus<T>(this IReadOnlyCollection<T> units, double subtrahend, Span<T> destination)
|
internal static void Minus<T>(this IReadOnlyCollection<T> units, double subtrahend, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -831,12 +667,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Minus(subtrahend);
|
if (units is T[] array) return array.Minus(subtrahend);
|
||||||
if (units is List<T> list) return list.Minus(subtrahend);
|
if (units is List<T> list) return list.Minus(subtrahend);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Minus(subtrahend, arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -851,12 +681,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Minus(subtrahend);
|
if (units is T?[] array) return array.Minus(subtrahend);
|
||||||
if (units is List<T?> list) return list.Minus(subtrahend);
|
if (units is List<T?> list) return list.Minus(subtrahend);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Minus(subtrahend, arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -871,12 +695,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return minuend.Minus(array);
|
if (units is T[] array) return minuend.Minus(array);
|
||||||
if (units is List<T> list) return minuend.Minus(list);
|
if (units is List<T> list) return minuend.Minus(list);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
minuend.Minus(arr, arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -891,12 +709,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return minuend.Minus(array);
|
if (units is T?[] array) return minuend.Minus(array);
|
||||||
if (units is List<T?> list) return minuend.Minus(list);
|
if (units is List<T?> list) return minuend.Minus(list);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
minuend.Minus(arr, arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -1339,76 +1151,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
return resultArray.WrapAsList<T, T>();
|
return resultArray.WrapAsList<T, T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static void Minus<T>(this ICollection<double> units, T divisor, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is double[] array) { array.Minus(divisor, destination); return; }
|
|
||||||
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).Minus(divisor, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
double invMinusisor = 1.0 / divisor.ToDouble();
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (item * invMinusisor).ToUnit<T>();
|
|
||||||
}
|
|
||||||
internal static void Minus<T>(this ICollection<double?> units, T divisor, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is double?[] array) { array.Minus(divisor, destination); return; }
|
|
||||||
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).Minus(divisor, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
double invMinusisor = 1.0 / divisor.ToDouble();
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (item.Value * invMinusisor).ToUnit<T>() : null;
|
|
||||||
}
|
|
||||||
internal static void Minus<T>(this T dividend, ICollection<double> units, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is double[] array) { dividend.Minus(array, destination); return; }
|
|
||||||
if (units is List<double> list) { dividend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (dividend.ToDouble() / item).ToUnit<T>();
|
|
||||||
}
|
|
||||||
internal static void Minus<T>(this T dividend, ICollection<double?> units, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is double?[] array) { dividend.Minus(array, destination); return; }
|
|
||||||
if (units is List<double?> list) { dividend.Minus(CollectionsMarshal.AsSpan(list), destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (dividend.ToDouble() / item.Value).ToUnit<T>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static void Minus<T>(this IReadOnlyCollection<double> units, T divisor, Span<T> destination)
|
internal static void Minus<T>(this IReadOnlyCollection<double> units, T divisor, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -1516,12 +1258,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is double[] array) return array.Minus(divisor);
|
if (units is double[] array) return array.Minus(divisor);
|
||||||
if (units is List<double> list) return list.Minus(divisor);
|
if (units is List<double> list) return list.Minus(divisor);
|
||||||
if (units is ICollection<double> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.MinusCore(divisor.ToDouble(), arr.Length, arr);
|
|
||||||
return arr.ReCast<T>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<double> roc)
|
if (units is IReadOnlyCollection<double> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -1536,12 +1272,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is double?[] array) return array.Minus(divisor);
|
if (units is double?[] array) return array.Minus(divisor);
|
||||||
if (units is List<double?> list) return list.Minus(divisor);
|
if (units is List<double?> list) return list.Minus(divisor);
|
||||||
if (units is ICollection<double?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.MinusCore(divisor.ToDouble(), arr.Length, arr);
|
|
||||||
return arr.ReCast<T>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<double?> roc)
|
if (units is IReadOnlyCollection<double?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -1556,12 +1286,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is double[] array) return dividend.Minus(array);
|
if (units is double[] array) return dividend.Minus(array);
|
||||||
if (units is List<double> list) return dividend.Minus(list);
|
if (units is List<double> list) return dividend.Minus(list);
|
||||||
if (units is ICollection<double> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
dividend.ToDouble().MinusCore(arr, arr.Length, arr);
|
|
||||||
return arr.ReCast<T>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<double> roc)
|
if (units is IReadOnlyCollection<double> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -1576,12 +1300,6 @@ internal static partial class CollectionsMinusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is double?[] array) return dividend.Minus(array);
|
if (units is double?[] array) return dividend.Minus(array);
|
||||||
if (units is List<double?> list) return dividend.Minus(list);
|
if (units is List<double?> list) return dividend.Minus(list);
|
||||||
if (units is ICollection<double?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
dividend.ToDouble().MinusCore(arr, arr.Length, arr);
|
|
||||||
return arr.ReCast<T>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<double?> roc)
|
if (units is IReadOnlyCollection<double?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
|
|||||||
@@ -162,53 +162,6 @@ internal static partial class CollectionsMultiplyExtensions
|
|||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R> => units.Mul<T, R>(multiplicator);
|
where R : struct, IMensuraUnit, IEquatable<R> => units.Mul<T, R>(multiplicator);
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static void Mul<T, R>(this ICollection<T> units, double multiplicator, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { MultiplyCore(array, multiplicator, count, destination); return; }
|
|
||||||
if (units is List<T> list) { MultiplyCore(CollectionsMarshal.AsSpan(list), multiplicator, count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (item.ToDouble() * multiplicator).ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static void Mul<T, R>(this ICollection<T?> units, double multiplicator, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { MultiplyCore(array, multiplicator, count, destination); return; }
|
|
||||||
if (units is List<T?> list) { MultiplyCore(CollectionsMarshal.AsSpan(list), multiplicator, count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (item.Value.ToDouble() * multiplicator).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static void Mul<T, R>(this double multiplicator, ICollection<T> units, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R> => units.Mul(multiplicator, destination);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static void Mul<T, R>(this double multiplicator, ICollection<T?> units, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R> => units.Mul(multiplicator, destination);
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static void Mul<T, R>(this IReadOnlyCollection<T> units, double multiplicator, Span<R> destination)
|
internal static void Mul<T, R>(this IReadOnlyCollection<T> units, double multiplicator, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -281,12 +234,6 @@ internal static partial class CollectionsMultiplyExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Mul<T, R>(multiplicator);
|
if (units is T[] array) return array.Mul<T, R>(multiplicator);
|
||||||
if (units is List<T> list) return list.Mul<T, R>(multiplicator);
|
if (units is List<T> list) return list.Mul<T, R>(multiplicator);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Mul(multiplicator, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -302,12 +249,6 @@ internal static partial class CollectionsMultiplyExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Mul<T, R>(multiplicator);
|
if (units is T?[] array) return array.Mul<T, R>(multiplicator);
|
||||||
if (units is List<T?> list) return list.Mul<T, R>(multiplicator);
|
if (units is List<T?> list) return list.Mul<T, R>(multiplicator);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Mul(multiplicator, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -424,49 +365,6 @@ internal static partial class CollectionsMultiplyExtensions
|
|||||||
internal static List<T?> Mul<T>(this double multiplicator, List<T?> units)
|
internal static List<T?> Mul<T>(this double multiplicator, List<T?> units)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul(multiplicator);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul(multiplicator);
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static void Mul<T>(this ICollection<T> units, double multiplicator, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { array.Mul(multiplicator, destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Mul(multiplicator, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (item.ToDouble() * multiplicator).ToUnit<T>();
|
|
||||||
}
|
|
||||||
internal static void Mul<T>(this ICollection<T?> units, double multiplicator, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.Mul(multiplicator, destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Mul(multiplicator, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (item.Value.ToDouble() * multiplicator).ToUnit<T>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static void Mul<T>(this double multiplicator, ICollection<T> units, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul<T>(multiplicator, destination);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static void Mul<T>(this double multiplicator, ICollection<T?> units, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul<T>(multiplicator, destination);
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static void Mul<T>(this IReadOnlyCollection<T> units, double multiplicator, Span<T> destination)
|
internal static void Mul<T>(this IReadOnlyCollection<T> units, double multiplicator, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -532,12 +430,6 @@ internal static partial class CollectionsMultiplyExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Mul(multiplicator);
|
if (units is T[] array) return array.Mul(multiplicator);
|
||||||
if (units is List<T> list) return list.Mul(multiplicator);
|
if (units is List<T> list) return list.Mul(multiplicator);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Mul(multiplicator, arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -552,12 +444,6 @@ internal static partial class CollectionsMultiplyExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Mul(multiplicator);
|
if (units is T?[] array) return array.Mul(multiplicator);
|
||||||
if (units is List<T?> list) return list.Mul(multiplicator);
|
if (units is List<T?> list) return list.Mul(multiplicator);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Mul(multiplicator, arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -832,49 +718,6 @@ internal static partial class CollectionsMultiplyExtensions
|
|||||||
internal static List<T?> Mul<T>(this T multiplicator, List<double?> units)
|
internal static List<T?> Mul<T>(this T multiplicator, List<double?> units)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul(multiplicator);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul(multiplicator);
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static void Mul<T>(this ICollection<double> units, T multiplicator, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is double[] array) { array.MultiplyCore(multiplicator.ToDouble(), array.Length, destination); return; }
|
|
||||||
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).MultiplyCore(multiplicator.ToDouble(), list.Count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (item * multiplicator.ToDouble()).ToUnit<T>();
|
|
||||||
}
|
|
||||||
internal static void Mul<T>(this ICollection<double?> units, T multiplicator, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is double?[] array) { array.MultiplyCore(multiplicator.ToDouble(), array.Length, destination); return; }
|
|
||||||
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).MultiplyCore(multiplicator.ToDouble(), list.Count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (item.Value * multiplicator.ToDouble()).ToUnit<T>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static void Mul<T>(this T multiplicator, ICollection<double> units, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul<T>(multiplicator, destination);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static void Mul<T>(this T multiplicator, ICollection<double?> units, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Mul<T>(multiplicator, destination);
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static void Mul<T>(this IReadOnlyCollection<double> units, T multiplicator, Span<T> destination)
|
internal static void Mul<T>(this IReadOnlyCollection<double> units, T multiplicator, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -940,12 +783,6 @@ internal static partial class CollectionsMultiplyExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is double[] array) return array.Mul(multiplicator);
|
if (units is double[] array) return array.Mul(multiplicator);
|
||||||
if (units is List<double> list) return list.Mul(multiplicator);
|
if (units is List<double> list) return list.Mul(multiplicator);
|
||||||
if (units is ICollection<double> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr);
|
|
||||||
return arr.ReCast<T>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<double> roc)
|
if (units is IReadOnlyCollection<double> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -960,12 +797,6 @@ internal static partial class CollectionsMultiplyExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is double?[] array) return array.Mul(multiplicator);
|
if (units is double?[] array) return array.Mul(multiplicator);
|
||||||
if (units is List<double?> list) return list.Mul(multiplicator);
|
if (units is List<double?> list) return list.Mul(multiplicator);
|
||||||
if (units is ICollection<double?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr);
|
|
||||||
return arr.ReCast<T>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<double?> roc)
|
if (units is IReadOnlyCollection<double?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
|
|||||||
@@ -163,53 +163,6 @@ internal static partial class CollectionsPlusExtensions
|
|||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R> => units.Plus<T, R>(summand);
|
where R : struct, IMensuraUnit, IEquatable<R> => units.Plus<T, R>(summand);
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static void Plus<T, R>(this ICollection<T> units, double summand, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { PlusCore(array, summand, count, destination); return; }
|
|
||||||
if (units is List<T> list) { PlusCore(CollectionsMarshal.AsSpan(list), summand, count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (item.ToDouble() + summand).ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static void Plus<T, R>(this ICollection<T?> units, double summand, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { PlusCore(array, summand, count, destination); return; }
|
|
||||||
if (units is List<T?> list) { PlusCore(CollectionsMarshal.AsSpan(list), summand, count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (item.Value.ToDouble() + summand).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static void Plus<T, R>(this double summand, ICollection<T> units, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R> => units.Plus(summand, destination);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static void Plus<T, R>(this double summand, ICollection<T?> units, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R> => units.Plus(summand, destination);
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static void Plus<T, R>(this IReadOnlyCollection<T> units, double summand, Span<R> destination)
|
internal static void Plus<T, R>(this IReadOnlyCollection<T> units, double summand, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -282,12 +235,6 @@ internal static partial class CollectionsPlusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Plus<T, R>(summand);
|
if (units is T[] array) return array.Plus<T, R>(summand);
|
||||||
if (units is List<T> list) return list.Plus<T, R>(summand);
|
if (units is List<T> list) return list.Plus<T, R>(summand);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Plus(summand, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -303,12 +250,6 @@ internal static partial class CollectionsPlusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Plus<T, R>(summand);
|
if (units is T?[] array) return array.Plus<T, R>(summand);
|
||||||
if (units is List<T?> list) return list.Plus<T, R>(summand);
|
if (units is List<T?> list) return list.Plus<T, R>(summand);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Plus(summand, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -425,49 +366,6 @@ internal static partial class CollectionsPlusExtensions
|
|||||||
internal static List<T?> Plus<T>(this double summand, List<T?> units)
|
internal static List<T?> Plus<T>(this double summand, List<T?> units)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static void Plus<T>(this ICollection<T> units, double summand, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { array.Plus(summand, destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Plus(summand, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (item.ToDouble() + summand).ToUnit<T>();
|
|
||||||
}
|
|
||||||
internal static void Plus<T>(this ICollection<T?> units, double summand, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.Plus(summand, destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Plus(summand, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (item.Value.ToDouble() + summand).ToUnit<T>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static void Plus<T>(this double summand, ICollection<T> units, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus<T>(summand, destination);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static void Plus<T>(this double summand, ICollection<T?> units, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus<T>(summand, destination);
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static void Plus<T>(this IReadOnlyCollection<T> units, double summand, Span<T> destination)
|
internal static void Plus<T>(this IReadOnlyCollection<T> units, double summand, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -533,12 +431,6 @@ internal static partial class CollectionsPlusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Plus(summand);
|
if (units is T[] array) return array.Plus(summand);
|
||||||
if (units is List<T> list) return list.Plus(summand);
|
if (units is List<T> list) return list.Plus(summand);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Plus(summand, arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -553,12 +445,6 @@ internal static partial class CollectionsPlusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Plus(summand);
|
if (units is T?[] array) return array.Plus(summand);
|
||||||
if (units is List<T?> list) return list.Plus(summand);
|
if (units is List<T?> list) return list.Plus(summand);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Plus(summand, arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -837,49 +723,6 @@ internal static partial class CollectionsPlusExtensions
|
|||||||
internal static List<T?> Plus<T>(this T summand, List<double?> units)
|
internal static List<T?> Plus<T>(this T summand, List<double?> units)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
|
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus(summand);
|
||||||
|
|
||||||
// === ICollection<T> ===
|
|
||||||
internal static void Plus<T>(this ICollection<double> units, T summand, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is double[] array) { array.PlusCore(summand.ToDouble(), array.Length, destination); return; }
|
|
||||||
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).PlusCore(summand.ToDouble(), list.Count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = (item + summand.ToDouble()).ToUnit<T>();
|
|
||||||
}
|
|
||||||
internal static void Plus<T>(this ICollection<double?> units, T summand, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is double?[] array) { array.PlusCore(summand.ToDouble(), array.Length, destination); return; }
|
|
||||||
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).PlusCore(summand.ToDouble(), list.Count, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? (item.Value + summand.ToDouble()).ToUnit<T>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static void Plus<T>(this T summand, ICollection<double> units, Span<T> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus<T>(summand, destination);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal static void Plus<T>(this T summand, ICollection<double?> units, Span<T?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T> => units.Plus<T>(summand, destination);
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<T> ===
|
// === IReadOnlyCollection<T> ===
|
||||||
internal static void Plus<T>(this IReadOnlyCollection<double> units, T summand, Span<T> destination)
|
internal static void Plus<T>(this IReadOnlyCollection<double> units, T summand, Span<T> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -945,12 +788,6 @@ internal static partial class CollectionsPlusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is double[] array) return array.Plus(summand);
|
if (units is double[] array) return array.Plus(summand);
|
||||||
if (units is List<double> list) return list.Plus(summand);
|
if (units is List<double> list) return list.Plus(summand);
|
||||||
if (units is ICollection<double> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.PlusCore(summand.ToDouble(), arr.Length, arr);
|
|
||||||
return arr.ReCast<T>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<double> roc)
|
if (units is IReadOnlyCollection<double> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -965,12 +802,6 @@ internal static partial class CollectionsPlusExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is double?[] array) return array.Plus(summand);
|
if (units is double?[] array) return array.Plus(summand);
|
||||||
if (units is List<double?> list) return list.Plus(summand);
|
if (units is List<double?> list) return list.Plus(summand);
|
||||||
if (units is ICollection<double?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.PlusCore(summand.ToDouble(), arr.Length, arr);
|
|
||||||
return arr.ReCast<T>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<double?> roc)
|
if (units is IReadOnlyCollection<double?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ internal static partial class CollectionsPow2Extensions
|
|||||||
|
|
||||||
// === ВТОРАЯ СТЕПЕНЬ ==========================================
|
// === ВТОРАЯ СТЕПЕНЬ ==========================================
|
||||||
|
|
||||||
// === Pow2Core2 === SIMD
|
// === Pow2Core === SIMD
|
||||||
internal static void Pow2Core2<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
|
internal static void Pow2Core<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
@@ -43,7 +43,7 @@ internal static partial class CollectionsPow2Extensions
|
|||||||
dstDouble[i] = val * val;
|
dstDouble[i] = val * val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal static void Pow2Core2<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
internal static void Pow2Core<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
@@ -106,7 +106,7 @@ internal static partial class CollectionsPow2Extensions
|
|||||||
if (len > destination.Length)
|
if (len > destination.Length)
|
||||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
units.Pow2Core2(len, destination);
|
units.Pow2Core(len, destination);
|
||||||
}
|
}
|
||||||
internal static void Pow2<T, R>(this ReadOnlySpan<T?> units, Span<R?> destination)
|
internal static void Pow2<T, R>(this ReadOnlySpan<T?> units, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -117,7 +117,7 @@ internal static partial class CollectionsPow2Extensions
|
|||||||
if (len > destination.Length)
|
if (len > destination.Length)
|
||||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
units.Pow2Core2(len, destination);
|
units.Pow2Core(len, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Array ===
|
// === Array ===
|
||||||
@@ -172,43 +172,6 @@ internal static partial class CollectionsPow2Extensions
|
|||||||
return resultArray.WrapAsList<R, R>();
|
return resultArray.WrapAsList<R, R>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<Length> ===
|
|
||||||
internal static void Pow2<T, R>(this ICollection<T> units, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { array.Pow2(destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow2(destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.ToDouble().QuickPow2().ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static void Pow2<T, R>(this ICollection<T?> units, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.Pow2(destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow2(destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? item.Value.ToDouble().QuickPow2().ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<Length> ===
|
// === IReadOnlyCollection<Length> ===
|
||||||
internal static void Pow2<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
|
internal static void Pow2<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -271,12 +234,6 @@ internal static partial class CollectionsPow2Extensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Pow2<T, R>();
|
if (units is T[] array) return array.Pow2<T, R>();
|
||||||
if (units is List<T> list) return list.Pow2<T, R>();
|
if (units is List<T> list) return list.Pow2<T, R>();
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Pow2Core2(arr.Length, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -292,12 +249,6 @@ internal static partial class CollectionsPow2Extensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Pow2<T, R>();
|
if (units is T?[] array) return array.Pow2<T, R>();
|
||||||
if (units is List<T?> list) return list.Pow2<T, R>();
|
if (units is List<T?> list) return list.Pow2<T, R>();
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Pow2(arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
|
|||||||
@@ -175,43 +175,6 @@ internal static partial class CollectionsPow3Extensions
|
|||||||
return resultArray.WrapAsList<R, R>();
|
return resultArray.WrapAsList<R, R>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<Length> ===
|
|
||||||
internal static void Pow3<T, R>(this ICollection<T> units, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { array.Pow3(destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow3(destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.ToDouble().QuickPow3().ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static void Pow3<T, R>(this ICollection<T?> units, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.Pow3(destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow3(destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? item.Value.ToDouble().QuickPow3().ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<Length> ===
|
// === IReadOnlyCollection<Length> ===
|
||||||
internal static void Pow3<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
|
internal static void Pow3<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -274,12 +237,6 @@ internal static partial class CollectionsPow3Extensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Pow3<T, R>();
|
if (units is T[] array) return array.Pow3<T, R>();
|
||||||
if (units is List<T> list) return list.Pow3<T, R>();
|
if (units is List<T> list) return list.Pow3<T, R>();
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.PowCore3(arr.Length, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -295,12 +252,6 @@ internal static partial class CollectionsPow3Extensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Pow3<T, R>();
|
if (units is T?[] array) return array.Pow3<T, R>();
|
||||||
if (units is List<T?> list) return list.Pow3<T, R>();
|
if (units is List<T?> list) return list.Pow3<T, R>();
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Pow3(arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
|
|||||||
@@ -222,43 +222,6 @@ internal static partial class CollectionsPowNExtensions
|
|||||||
return resultArray.WrapAsList<R, R>();
|
return resultArray.WrapAsList<R, R>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<Length> ===
|
|
||||||
internal static void Pow<T, R>(this ICollection<T> units, int power, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { array.Pow(power, destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.ToDouble().QuickPow(power).ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static void Pow<T, R>(this ICollection<T?> units, int power, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.Pow(power, destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? item.Value.ToDouble().QuickPow(power).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<Length> ===
|
// === IReadOnlyCollection<Length> ===
|
||||||
internal static void Pow<T, R>(this IReadOnlyCollection<T> units, int power, Span<R> destination)
|
internal static void Pow<T, R>(this IReadOnlyCollection<T> units, int power, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -321,12 +284,6 @@ internal static partial class CollectionsPowNExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Pow<T, R>(power);
|
if (units is T[] array) return array.Pow<T, R>(power);
|
||||||
if (units is List<T> list) return list.Pow<T, R>(power);
|
if (units is List<T> list) return list.Pow<T, R>(power);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.PowCore(power, arr.Length, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -342,12 +299,6 @@ internal static partial class CollectionsPowNExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Pow<T, R>(power);
|
if (units is T?[] array) return array.Pow<T, R>(power);
|
||||||
if (units is List<T?> list) return list.Pow<T, R>(power);
|
if (units is List<T?> list) return list.Pow<T, R>(power);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Pow(power, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -534,43 +485,6 @@ internal static partial class CollectionsPowNExtensions
|
|||||||
return result.WrapAsList<R, R>();
|
return result.WrapAsList<R, R>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<Length> ===
|
|
||||||
internal static void Pow<T, R>(this ICollection<T> units, double power, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { array.Pow(power, destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (T item in units)
|
|
||||||
destination[i++] = Math.Pow(item.ToDouble(), power).ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static void Pow<T, R>(this ICollection<T?> units, double power, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.Pow(power, destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow(power, destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (T? item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? Math.Pow(item.Value.ToDouble(), power).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<Length> ===
|
// === IReadOnlyCollection<Length> ===
|
||||||
internal static void Pow<T, R>(this IReadOnlyCollection<T> units, double power, Span<R> destination)
|
internal static void Pow<T, R>(this IReadOnlyCollection<T> units, double power, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -633,12 +547,6 @@ internal static partial class CollectionsPowNExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Pow<T, R>(power);
|
if (units is T[] array) return array.Pow<T, R>(power);
|
||||||
if (units is List<T> list) return list.Pow<T, R>(power);
|
if (units is List<T> list) return list.Pow<T, R>(power);
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Pow(power, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -654,12 +562,6 @@ internal static partial class CollectionsPowNExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Pow<T, R>(power);
|
if (units is T?[] array) return array.Pow<T, R>(power);
|
||||||
if (units is List<T?> list) return list.Pow<T, R>(power);
|
if (units is List<T?> list) return list.Pow<T, R>(power);
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Pow(power, arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
|
|||||||
215
QWERTYkez.Mensura/Extensions/CollectionsRootOfCubeExtensions.cs
Normal file
215
QWERTYkez.Mensura/Extensions/CollectionsRootOfCubeExtensions.cs
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
using System.Runtime.Intrinsics.X86;
|
||||||
|
|
||||||
|
namespace QWERTYkez.Mensura.Extensions;
|
||||||
|
|
||||||
|
internal static partial class CollectionsRootOfCubeExtensions
|
||||||
|
{
|
||||||
|
// === CbrtCore === SIMD
|
||||||
|
internal static unsafe void CbrtCore<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
// Прямой каст без проверок размеров
|
||||||
|
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
||||||
|
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
|
||||||
|
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
|
||||||
|
|
||||||
|
// 1. SIMD путь (AVX)
|
||||||
|
if (Avx.IsSupported && len >= 4)
|
||||||
|
{
|
||||||
|
int simdEnd = len & ~3;
|
||||||
|
for (; i < simdEnd; i += 4)
|
||||||
|
{
|
||||||
|
double* pSrc = (double*)Unsafe.AsPointer(ref Unsafe.Add(ref srcRef, i));
|
||||||
|
double* pDst = (double*)Unsafe.AsPointer(ref Unsafe.Add(ref dstRef, i));
|
||||||
|
|
||||||
|
// Используем LoadVector256 для максимально быстрой обработки 4-х double
|
||||||
|
Avx.Store(pDst, Avx.Sqrt(Avx.LoadVector256(pSrc)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2. Fallback путь для остатка
|
||||||
|
for (; i < len; i++)
|
||||||
|
{
|
||||||
|
Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static void CbrtCore<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
||||||
|
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
||||||
|
int i = 0, unrollEnd = len & ~3;
|
||||||
|
|
||||||
|
for (; i < unrollEnd; i += 4)
|
||||||
|
{
|
||||||
|
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i).HasValue ? Math.Sqrt(Unsafe.Add(ref srcRef, i)!.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
|
Unsafe.Add(ref dstRef, i + 1) = Unsafe.Add(ref srcRef, i + 1).HasValue ? Math.Sqrt(Unsafe.Add(ref srcRef, i + 1)!.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
|
Unsafe.Add(ref dstRef, i + 2) = Unsafe.Add(ref srcRef, i + 2).HasValue ? Math.Sqrt(Unsafe.Add(ref srcRef, i + 2)!.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
|
Unsafe.Add(ref dstRef, i + 3) = Unsafe.Add(ref srcRef, i + 3).HasValue ? Math.Sqrt(Unsafe.Add(ref srcRef, i + 3)!.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
|
}
|
||||||
|
for (; i < len; i++)
|
||||||
|
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i).HasValue ? Math.Sqrt(Unsafe.Add(ref srcRef, i)!.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// === ReadOnlySpan ===
|
||||||
|
internal static void Cbrt<T, R>(this ReadOnlySpan<T> units, Span<R> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.CbrtCore(len, destination);
|
||||||
|
}
|
||||||
|
internal static void Cbrt<T, R>(this ReadOnlySpan<T?> units, Span<R?> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
if (units.IsEmpty) return;
|
||||||
|
int len = units.Length;
|
||||||
|
if (len > destination.Length)
|
||||||
|
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
||||||
|
|
||||||
|
units.CbrtCore(len, destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Array ===
|
||||||
|
internal static R[] Cbrt<T, R>(this T[] units)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
if (units.Length == 0) return [];
|
||||||
|
|
||||||
|
var result = new R[units.Length];
|
||||||
|
Cbrt(units, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
internal static R?[] Cbrt<T, R>(this T?[] units)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
if (units.Length == 0) return [];
|
||||||
|
|
||||||
|
var result = new R?[units.Length];
|
||||||
|
Cbrt(units, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// === List ===
|
||||||
|
internal static List<R> Cbrt<T, R>(this List<T> units)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
int len = units.Count;
|
||||||
|
if (len == 0) return [];
|
||||||
|
|
||||||
|
var resultArray = new R[len];
|
||||||
|
Cbrt(CollectionsMarshal.AsSpan(units), resultArray);
|
||||||
|
return resultArray.WrapAsList<R, R>();
|
||||||
|
}
|
||||||
|
internal static List<R?> Cbrt<T, R>(this List<T?> units)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
int len = units.Count;
|
||||||
|
if (len == 0) return [];
|
||||||
|
|
||||||
|
var resultArray = new R?[len];
|
||||||
|
Cbrt(CollectionsMarshal.AsSpan(units), resultArray);
|
||||||
|
return resultArray.WrapAsList<R, R>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// === IReadOnlyCollection ===
|
||||||
|
internal static void Cbrt<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
if (units is null) return;
|
||||||
|
int count = units.Count;
|
||||||
|
if (count == 0) return;
|
||||||
|
if (destination.Length < count) throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
|
if (units is T[] array) { array.AsSpan().CbrtCore(count, destination); return; }
|
||||||
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).CbrtCore(count, destination); return; }
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
ref R dstRef = ref MemoryMarshal.GetReference(destination);
|
||||||
|
foreach (T item in units) Unsafe.Add(ref dstRef, i++) = Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
||||||
|
}
|
||||||
|
internal static void Cbrt<T, R>(this IReadOnlyCollection<T?> units, Span<R?> destination)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
if (units is null) return;
|
||||||
|
int count = units.Count;
|
||||||
|
if (count == 0) return;
|
||||||
|
if (destination.Length < count)
|
||||||
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
|
if (units is T?[] array) { array.Cbrt(destination); return; }
|
||||||
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Cbrt(destination); return; }
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (T? item in units)
|
||||||
|
destination[i++] = item.HasValue
|
||||||
|
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// === IEnumerable + yield ===
|
||||||
|
internal static IEnumerable<R> SqrtIterator3<T, R>(this IEnumerable<T> units)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
foreach (var item in units) yield return Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
||||||
|
}
|
||||||
|
internal static IEnumerable<R?> SqrtNullableIterator3<T, R>(this IEnumerable<T?> units)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
foreach (var item in units)
|
||||||
|
yield return item.HasValue
|
||||||
|
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// === IEnumerable ===
|
||||||
|
internal static IEnumerable<R> Cbrt<T, R>(this IEnumerable<T> units)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
if (units is T[] array) return array.Cbrt<T, R>();
|
||||||
|
if (units is List<T> list) return list.Cbrt<T, R>();
|
||||||
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
|
{
|
||||||
|
var arr = roc.ToArray();
|
||||||
|
arr.Cbrt(arr);
|
||||||
|
return arr.ReCast<T, R>();
|
||||||
|
}
|
||||||
|
else return SqrtIterator3<T, R>(units);
|
||||||
|
}
|
||||||
|
internal static IEnumerable<R?> Cbrt<T, R>(this IEnumerable<T?> units)
|
||||||
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
|
{
|
||||||
|
if (units is null) return null!;
|
||||||
|
if (units is T?[] array) return array.Cbrt<T, R>();
|
||||||
|
if (units is List<T?> list) return list.Cbrt<T, R>();
|
||||||
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
|
{
|
||||||
|
var arr = roc.ToArray();
|
||||||
|
arr.Cbrt(arr);
|
||||||
|
return arr.ReCast<T, R>();
|
||||||
|
}
|
||||||
|
else return SqrtNullableIterator3<T, R>(units);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace QWERTYkez.Mensura.Extensions;
|
namespace QWERTYkez.Mensura.Extensions;
|
||||||
|
|
||||||
internal static partial class CollectionsSqrtExtensions
|
internal static partial class CollectionsRootOfSquareExtensions
|
||||||
{
|
{
|
||||||
// === SqrtCore === SIMD
|
// === SqrtCore === SIMD
|
||||||
internal static unsafe void SqrtCore<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
|
internal static unsafe void SqrtCore<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
|
||||||
@@ -13,11 +13,10 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
|
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
|
||||||
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
|
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
|
||||||
|
|
||||||
// 1. ПУТЬ AVX (x64 Процессоры Intel/AMD) — обрабатываем по 4 элемента double
|
// 1. ПУТЬ AVX2 / AVX (x64 Процессоры) — обрабатываем по 4 элемента double за такт
|
||||||
if (Avx.IsSupported && len >= 4)
|
if (Avx.IsSupported && len >= 4)
|
||||||
{
|
{
|
||||||
int simdEnd = len & ~3;
|
int simdEnd = len & ~3;
|
||||||
@@ -26,18 +25,16 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
|
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
|
||||||
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
|
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
|
||||||
|
|
||||||
// Получаем указатели через Unsafe.AsPointer
|
|
||||||
double* pSrc = (double*)Unsafe.AsPointer(ref currentSrc);
|
double* pSrc = (double*)Unsafe.AsPointer(ref currentSrc);
|
||||||
double* pDst = (double*)Unsafe.AsPointer(ref currentDst);
|
double* pDst = (double*)Unsafe.AsPointer(ref currentDst);
|
||||||
|
|
||||||
// Выровненная загрузка (требует, чтобы pSrc был кратен 32)
|
// Используем Load вместо LoadVector256 (Load безопасен к невыровненной по 32-байтам памяти)
|
||||||
var v = Avx.LoadVector256(pSrc);
|
var v = Avx.LoadVector256(pSrc);
|
||||||
var sqrtV = Avx.Sqrt(v);
|
var sqrtV = Avx.Sqrt(v);
|
||||||
// Выровненное сохранение
|
|
||||||
Avx.Store(pDst, sqrtV);
|
Avx.Store(pDst, sqrtV);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 2. ПУТЬ VECTOR (ARM64 / Apple Silicon / Старые CPU без AVX)
|
// 2. КРОССПЛАТФОРМЕННЫЙ VECTOR (ARM64 / Apple Silicon / NEON / SIMD Fallback)
|
||||||
else if (Vector.IsHardwareAccelerated && len >= Vector<double>.Count)
|
else if (Vector.IsHardwareAccelerated && len >= Vector<double>.Count)
|
||||||
{
|
{
|
||||||
int vCount = Vector<double>.Count;
|
int vCount = Vector<double>.Count;
|
||||||
@@ -45,18 +42,13 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
|
|
||||||
for (; i < simdEnd; i += vCount)
|
for (; i < simdEnd; i += vCount)
|
||||||
{
|
{
|
||||||
// Используем Span для кроссплатформенного создания вектора
|
|
||||||
var v = new Vector<double>(srcDouble.Slice(i, vCount));
|
var v = new Vector<double>(srcDouble.Slice(i, vCount));
|
||||||
|
|
||||||
// Кроссплатформенный аппаратный корень (на ARM превратится в NEON инструкцию)
|
|
||||||
var sqrtV = Vector.SquareRoot(v);
|
var sqrtV = Vector.SquareRoot(v);
|
||||||
|
|
||||||
// Копируем напрямую в целевой Span
|
|
||||||
sqrtV.CopyTo(dstDouble.Slice(i, vCount));
|
sqrtV.CopyTo(dstDouble.Slice(i, vCount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Хвост массива (или обычный расчет, если SIMD на процессоре недоступен)
|
// 3. ХВОСТ МАССИВА (или работа на старых CPU)
|
||||||
for (; i < len; i++)
|
for (; i < len; i++)
|
||||||
{
|
{
|
||||||
Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i));
|
Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i));
|
||||||
@@ -66,47 +58,41 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
{
|
{
|
||||||
// Получаем прямые ref-ссылки на начало буферов за 0 тактов процессора
|
|
||||||
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
||||||
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
|
int unrollEnd = len & ~3;
|
||||||
|
|
||||||
// 1. ОСНОВНОЙ ЦИКЛ: Конвейерная обработка по 4 элемента за итерацию
|
// ОСНОВНОЙ ЦИКЛ: Конвейерное чтение по 4 элемента (Развертка цикла повышает ILP процессора)
|
||||||
for (; i < unrollEnd; i += 4)
|
for (; i < unrollEnd; i += 4)
|
||||||
{
|
{
|
||||||
T? u0 = Unsafe.Add(ref srcRef, i);
|
ref readonly T? u0 = ref Unsafe.Add(ref srcRef, i);
|
||||||
T? u1 = Unsafe.Add(ref srcRef, i + 1);
|
ref readonly T? u1 = ref Unsafe.Add(ref srcRef, i + 1);
|
||||||
T? u2 = Unsafe.Add(ref srcRef, i + 2);
|
ref readonly T? u2 = ref Unsafe.Add(ref srcRef, i + 2);
|
||||||
T? u3 = Unsafe.Add(ref srcRef, i + 3);
|
ref readonly T? u3 = ref Unsafe.Add(ref srcRef, i + 3);
|
||||||
|
|
||||||
// Получаем ref-ссылки на целевые ячейки типа R? (zero-cost адресация)
|
|
||||||
ref var d0 = ref Unsafe.Add(ref dstRef, i);
|
ref var d0 = ref Unsafe.Add(ref dstRef, i);
|
||||||
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
|
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
|
||||||
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
|
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
|
||||||
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
||||||
|
|
||||||
// Считаем нативный корень прямо в регистрах и трансформируем тип из T в R по месту
|
|
||||||
d0 = u0.HasValue ? Math.Sqrt(u0.Value.ToDouble()).ToUnit<R>() : null;
|
d0 = u0.HasValue ? Math.Sqrt(u0.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
d1 = u1.HasValue ? Math.Sqrt(u1.Value.ToDouble()).ToUnit<R>() : null;
|
d1 = u1.HasValue ? Math.Sqrt(u1.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
d2 = u2.HasValue ? Math.Sqrt(u2.Value.ToDouble()).ToUnit<R>() : null;
|
d2 = u2.HasValue ? Math.Sqrt(u2.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
d3 = u3.HasValue ? Math.Sqrt(u3.Value.ToDouble()).ToUnit<R>() : null;
|
d3 = u3.HasValue ? Math.Sqrt(u3.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
// ХВОСТ ЦИКЛА: Остаток элементов
|
||||||
for (; i < len; i++)
|
for (; i < len; i++)
|
||||||
{
|
{
|
||||||
T? unit = Unsafe.Add(ref srcRef, i);
|
ref readonly T? unit = ref Unsafe.Add(ref srcRef, i);
|
||||||
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
||||||
dst = unit.HasValue ? Math.Sqrt(unit.Value.ToDouble()).ToUnit<R>() : null;
|
dst = unit.HasValue ? Math.Sqrt(unit.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === ReadOnlySpan API ===
|
||||||
|
|
||||||
|
|
||||||
// === ReadOnlySpan ===
|
|
||||||
internal static void Sqrt<T, R>(this ReadOnlySpan<T> units, Span<R> destination)
|
internal static void Sqrt<T, R>(this ReadOnlySpan<T> units, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
@@ -130,7 +116,7 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
units.SqrtCore(len, destination);
|
units.SqrtCore(len, destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Array ===
|
// === Array API ===
|
||||||
internal static R[] Sqrt<T, R>(this T[] units)
|
internal static R[] Sqrt<T, R>(this T[] units)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
@@ -139,7 +125,7 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
if (units.Length == 0) return [];
|
if (units.Length == 0) return [];
|
||||||
|
|
||||||
var result = new R[units.Length];
|
var result = new R[units.Length];
|
||||||
Sqrt(units, result);
|
units.AsSpan().SqrtCore(units.Length, result.AsSpan());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
internal static R?[] Sqrt<T, R>(this T?[] units)
|
internal static R?[] Sqrt<T, R>(this T?[] units)
|
||||||
@@ -150,11 +136,11 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
if (units.Length == 0) return [];
|
if (units.Length == 0) return [];
|
||||||
|
|
||||||
var result = new R?[units.Length];
|
var result = new R?[units.Length];
|
||||||
Sqrt(units, result);
|
units.AsSpan().SqrtCore(units.Length, result.AsSpan());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === List<Length> ===
|
// === List API ===
|
||||||
internal static List<R> Sqrt<T, R>(this List<T> units)
|
internal static List<R> Sqrt<T, R>(this List<T> units)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
@@ -164,7 +150,7 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
|
|
||||||
var resultArray = new R[len];
|
var resultArray = new R[len];
|
||||||
Sqrt(CollectionsMarshal.AsSpan(units), resultArray);
|
CollectionsMarshal.AsSpan(units).SqrtCore(len, resultArray.AsSpan());
|
||||||
return resultArray.WrapAsList<R, R>();
|
return resultArray.WrapAsList<R, R>();
|
||||||
}
|
}
|
||||||
internal static List<R?> Sqrt<T, R>(this List<T?> units)
|
internal static List<R?> Sqrt<T, R>(this List<T?> units)
|
||||||
@@ -176,48 +162,11 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
if (len == 0) return [];
|
if (len == 0) return [];
|
||||||
|
|
||||||
var resultArray = new R?[len];
|
var resultArray = new R?[len];
|
||||||
Sqrt(CollectionsMarshal.AsSpan(units), resultArray);
|
CollectionsMarshal.AsSpan(units).SqrtCore(len, resultArray.AsSpan());
|
||||||
return resultArray.WrapAsList<R, R>();
|
return resultArray.WrapAsList<R, R>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === ICollection<Length> ===
|
// === IReadOnlyCollection ===
|
||||||
internal static void Sqrt<T, R>(this ICollection<T> units, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { array.Sqrt(destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Sqrt(destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (T item in units)
|
|
||||||
destination[i++] = Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static void Sqrt<T, R>(this ICollection<T?> units, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.Sqrt(destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Sqrt(destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (T? item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<Length> ===
|
|
||||||
internal static void Sqrt<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
|
internal static void Sqrt<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
@@ -228,12 +177,16 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
if (destination.Length < count)
|
if (destination.Length < count)
|
||||||
throw new ArgumentException("Destination too short");
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
if (units is T[] array) { array.Sqrt(destination); return; }
|
if (units is T[] array) { array.AsSpan().SqrtCore(count, destination); return; }
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Sqrt(destination); return; }
|
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).SqrtCore(count, destination); return; }
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
ref R dstRef = ref MemoryMarshal.GetReference(destination);
|
||||||
foreach (T item in units)
|
foreach (T item in units)
|
||||||
destination[i++] = Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
{
|
||||||
|
if ((uint)i >= (uint)count) break;
|
||||||
|
Unsafe.Add(ref dstRef, i++) = Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
internal static void Sqrt<T, R>(this IReadOnlyCollection<T?> units, Span<R?> destination)
|
internal static void Sqrt<T, R>(this IReadOnlyCollection<T?> units, Span<R?> destination)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
@@ -245,16 +198,20 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
if (destination.Length < count)
|
if (destination.Length < count)
|
||||||
throw new ArgumentException("Destination too short");
|
throw new ArgumentException("Destination too short");
|
||||||
|
|
||||||
if (units is T?[] array) { array.Sqrt(destination); return; }
|
if (units is T?[] array) { array.AsSpan().SqrtCore(count, destination); return; }
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Sqrt(destination); return; }
|
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).SqrtCore(count, destination); return; }
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
ref R? dstRef = ref MemoryMarshal.GetReference(destination);
|
||||||
foreach (T? item in units)
|
foreach (T? item in units)
|
||||||
destination[i++] = item.HasValue
|
{
|
||||||
|
if ((uint)i >= (uint)count) break;
|
||||||
|
Unsafe.Add(ref dstRef, i++) = item.HasValue
|
||||||
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === IEnumerable<Length> + yield ===
|
// === IEnumerable Iterators ===
|
||||||
internal static IEnumerable<R> SqrtIterator<T, R>(this IEnumerable<T> units)
|
internal static IEnumerable<R> SqrtIterator<T, R>(this IEnumerable<T> units)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
@@ -271,7 +228,7 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// === IEnumerable<Length> ===
|
// === IEnumerable API ===
|
||||||
internal static IEnumerable<R> Sqrt<T, R>(this IEnumerable<T> units)
|
internal static IEnumerable<R> Sqrt<T, R>(this IEnumerable<T> units)
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
where T : struct, IMensuraUnit, IEquatable<T>
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
where R : struct, IMensuraUnit, IEquatable<R>
|
||||||
@@ -279,12 +236,6 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T[] array) return array.Sqrt<T, R>();
|
if (units is T[] array) return array.Sqrt<T, R>();
|
||||||
if (units is List<T> list) return list.Sqrt<T, R>();
|
if (units is List<T> list) return list.Sqrt<T, R>();
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Sqrt(arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
if (units is IReadOnlyCollection<T> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -300,12 +251,6 @@ internal static partial class CollectionsSqrtExtensions
|
|||||||
if (units is null) return null!;
|
if (units is null) return null!;
|
||||||
if (units is T?[] array) return array.Sqrt<T, R>();
|
if (units is T?[] array) return array.Sqrt<T, R>();
|
||||||
if (units is List<T?> list) return list.Sqrt<T, R>();
|
if (units is List<T?> list) return list.Sqrt<T, R>();
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Sqrt(arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
if (units is IReadOnlyCollection<T?> roc)
|
||||||
{
|
{
|
||||||
var arr = roc.ToArray();
|
var arr = roc.ToArray();
|
||||||
@@ -1,317 +0,0 @@
|
|||||||
using System.Runtime.Intrinsics.X86;
|
|
||||||
|
|
||||||
namespace QWERTYkez.Mensura.Extensions;
|
|
||||||
|
|
||||||
internal static partial class CollectionsSqrt3Extensions
|
|
||||||
{
|
|
||||||
// === SqrtCore3 === SIMD
|
|
||||||
internal static unsafe void SqrtCore3<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
|
|
||||||
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
ref double srcRef = ref MemoryMarshal.GetReference(srcDouble);
|
|
||||||
ref double dstRef = ref MemoryMarshal.GetReference(dstDouble);
|
|
||||||
|
|
||||||
// 1. ПУТЬ AVX (x64 Процессоры Intel/AMD) — обрабатываем по 4 элемента double
|
|
||||||
if (Avx.IsSupported && len >= 4)
|
|
||||||
{
|
|
||||||
int simdEnd = len & ~3;
|
|
||||||
for (; i < simdEnd; i += 4)
|
|
||||||
{
|
|
||||||
ref double currentSrc = ref Unsafe.Add(ref srcRef, i);
|
|
||||||
ref double currentDst = ref Unsafe.Add(ref dstRef, i);
|
|
||||||
|
|
||||||
// Получаем указатели через Unsafe.AsPointer
|
|
||||||
double* pSrc = (double*)Unsafe.AsPointer(ref currentSrc);
|
|
||||||
double* pDst = (double*)Unsafe.AsPointer(ref currentDst);
|
|
||||||
|
|
||||||
// Выровненная загрузка (требует, чтобы pSrc был кратен 32)
|
|
||||||
var v = Avx.LoadVector256(pSrc);
|
|
||||||
var sqrtV = Avx.Sqrt(v);
|
|
||||||
// Выровненное сохранение
|
|
||||||
Avx.Store(pDst, sqrtV);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 2. ПУТЬ VECTOR (ARM64 / Apple Silicon / Старые CPU без AVX)
|
|
||||||
else if (Vector.IsHardwareAccelerated && len >= Vector<double>.Count)
|
|
||||||
{
|
|
||||||
int vCount = Vector<double>.Count;
|
|
||||||
int simdEnd = len & ~(vCount - 1);
|
|
||||||
|
|
||||||
for (; i < simdEnd; i += vCount)
|
|
||||||
{
|
|
||||||
// Используем Span для кроссплатформенного создания вектора
|
|
||||||
var v = new Vector<double>(srcDouble.Slice(i, vCount));
|
|
||||||
|
|
||||||
// Кроссплатформенный аппаратный корень (на ARM превратится в NEON инструкцию)
|
|
||||||
var sqrtV = Vector.SquareRoot(v);
|
|
||||||
|
|
||||||
// Копируем напрямую в целевой Span
|
|
||||||
sqrtV.CopyTo(dstDouble.Slice(i, vCount));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Хвост массива (или обычный расчет, если SIMD на процессоре недоступен)
|
|
||||||
for (; i < len; i++)
|
|
||||||
{
|
|
||||||
Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static void SqrtCore3<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
// Получаем прямые ref-ссылки на начало буферов за 0 тактов процессора
|
|
||||||
ref var srcRef = ref MemoryMarshal.GetReference(units);
|
|
||||||
ref var dstRef = ref MemoryMarshal.GetReference(destination);
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
int unrollEnd = len & ~3; // Граница развернутого цикла (кратная 4)
|
|
||||||
|
|
||||||
// 1. ОСНОВНОЙ ЦИКЛ: Конвейерная обработка по 4 элемента за итерацию
|
|
||||||
for (; i < unrollEnd; i += 4)
|
|
||||||
{
|
|
||||||
T? u0 = Unsafe.Add(ref srcRef, i);
|
|
||||||
T? u1 = Unsafe.Add(ref srcRef, i + 1);
|
|
||||||
T? u2 = Unsafe.Add(ref srcRef, i + 2);
|
|
||||||
T? u3 = Unsafe.Add(ref srcRef, i + 3);
|
|
||||||
|
|
||||||
// Получаем ref-ссылки на целевые ячейки типа R? (zero-cost адресация)
|
|
||||||
ref var d0 = ref Unsafe.Add(ref dstRef, i);
|
|
||||||
ref var d1 = ref Unsafe.Add(ref dstRef, i + 1);
|
|
||||||
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
|
|
||||||
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
|
|
||||||
|
|
||||||
// Считаем нативный корень прямо в регистрах и трансформируем тип из T в R по месту
|
|
||||||
d0 = u0.HasValue ? Math.Sqrt(u0.Value.ToDouble()).ToUnit<R>() : null;
|
|
||||||
d1 = u1.HasValue ? Math.Sqrt(u1.Value.ToDouble()).ToUnit<R>() : null;
|
|
||||||
d2 = u2.HasValue ? Math.Sqrt(u2.Value.ToDouble()).ToUnit<R>() : null;
|
|
||||||
d3 = u3.HasValue ? Math.Sqrt(u3.Value.ToDouble()).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
|
|
||||||
for (; i < len; i++)
|
|
||||||
{
|
|
||||||
T? unit = Unsafe.Add(ref srcRef, i);
|
|
||||||
ref var dst = ref Unsafe.Add(ref dstRef, i);
|
|
||||||
dst = unit.HasValue ? Math.Sqrt(unit.Value.ToDouble()).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// === ReadOnlySpan ===
|
|
||||||
internal static void Sqrt3<T, R>(this ReadOnlySpan<T> units, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units.IsEmpty) return;
|
|
||||||
int len = units.Length;
|
|
||||||
if (len > destination.Length)
|
|
||||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
|
||||||
|
|
||||||
units.SqrtCore3(len, destination);
|
|
||||||
}
|
|
||||||
internal static void Sqrt3<T, R>(this ReadOnlySpan<T?> units, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units.IsEmpty) return;
|
|
||||||
int len = units.Length;
|
|
||||||
if (len > destination.Length)
|
|
||||||
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
|
|
||||||
|
|
||||||
units.SqrtCore3(len, destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
// === Array ===
|
|
||||||
internal static R[] Sqrt3<T, R>(this T[] units)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return null!;
|
|
||||||
if (units.Length == 0) return [];
|
|
||||||
|
|
||||||
var result = new R[units.Length];
|
|
||||||
Sqrt3(units, result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
internal static R?[] Sqrt3<T, R>(this T?[] units)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return null!;
|
|
||||||
if (units.Length == 0) return [];
|
|
||||||
|
|
||||||
var result = new R?[units.Length];
|
|
||||||
Sqrt3(units, result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === List<Length> ===
|
|
||||||
internal static List<R> Sqrt3<T, R>(this List<T> units)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return null!;
|
|
||||||
int len = units.Count;
|
|
||||||
if (len == 0) return [];
|
|
||||||
|
|
||||||
var resultArray = new R[len];
|
|
||||||
Sqrt3(CollectionsMarshal.AsSpan(units), resultArray);
|
|
||||||
return resultArray.WrapAsList<R, R>();
|
|
||||||
}
|
|
||||||
internal static List<R?> Sqrt3<T, R>(this List<T?> units)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return null!;
|
|
||||||
int len = units.Count;
|
|
||||||
if (len == 0) return [];
|
|
||||||
|
|
||||||
var resultArray = new R?[len];
|
|
||||||
Sqrt3(CollectionsMarshal.AsSpan(units), resultArray);
|
|
||||||
return resultArray.WrapAsList<R, R>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// === ICollection<Length> ===
|
|
||||||
internal static void Sqrt3<T, R>(this ICollection<T> units, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { array.Sqrt3(destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Sqrt3(destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (T item in units)
|
|
||||||
destination[i++] = Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static void Sqrt3<T, R>(this ICollection<T?> units, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.Sqrt3(destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Sqrt3(destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (T? item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IReadOnlyCollection<Length> ===
|
|
||||||
internal static void Sqrt3<T, R>(this IReadOnlyCollection<T> units, Span<R> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T[] array) { array.Sqrt3(destination); return; }
|
|
||||||
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Sqrt3(destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (T item in units)
|
|
||||||
destination[i++] = Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static void Sqrt3<T, R>(this IReadOnlyCollection<T?> units, Span<R?> destination)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return;
|
|
||||||
int count = units.Count;
|
|
||||||
if (count == 0) return;
|
|
||||||
if (destination.Length < count)
|
|
||||||
throw new ArgumentException("Destination too short");
|
|
||||||
|
|
||||||
if (units is T?[] array) { array.Sqrt3(destination); return; }
|
|
||||||
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Sqrt3(destination); return; }
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (T? item in units)
|
|
||||||
destination[i++] = item.HasValue
|
|
||||||
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IEnumerable<Length> + yield ===
|
|
||||||
internal static IEnumerable<R> SqrtIterator3<T, R>(this IEnumerable<T> units)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
foreach (var item in units)
|
|
||||||
yield return Math.Sqrt(item.ToDouble()).ToUnit<R>();
|
|
||||||
}
|
|
||||||
internal static IEnumerable<R?> SqrtNullableIterator3<T, R>(this IEnumerable<T?> units)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
foreach (var item in units)
|
|
||||||
yield return item.HasValue
|
|
||||||
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === IEnumerable<Length> ===
|
|
||||||
internal static IEnumerable<R> Sqrt3<T, R>(this IEnumerable<T> units)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return null!;
|
|
||||||
if (units is T[] array) return array.Sqrt3<T, R>();
|
|
||||||
if (units is List<T> list) return list.Sqrt3<T, R>();
|
|
||||||
if (units is ICollection<T> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Sqrt3(arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T> roc)
|
|
||||||
{
|
|
||||||
var arr = roc.ToArray();
|
|
||||||
arr.Sqrt3(arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
else return SqrtIterator3<T, R>(units);
|
|
||||||
}
|
|
||||||
internal static IEnumerable<R?> Sqrt3<T, R>(this IEnumerable<T?> units)
|
|
||||||
where T : struct, IMensuraUnit, IEquatable<T>
|
|
||||||
where R : struct, IMensuraUnit, IEquatable<R>
|
|
||||||
{
|
|
||||||
if (units is null) return null!;
|
|
||||||
if (units is T?[] array) return array.Sqrt3<T, R>();
|
|
||||||
if (units is List<T?> list) return list.Sqrt3<T, R>();
|
|
||||||
if (units is ICollection<T?> col)
|
|
||||||
{
|
|
||||||
var arr = col.ToArray();
|
|
||||||
arr.Sqrt3(arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
if (units is IReadOnlyCollection<T?> roc)
|
|
||||||
{
|
|
||||||
var arr = roc.ToArray();
|
|
||||||
arr.Sqrt3(arr);
|
|
||||||
return arr.ReCast<T, R>();
|
|
||||||
}
|
|
||||||
else return SqrtNullableIterator3<T, R>(units);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,16 @@
|
|||||||
namespace QWERTYkez.Mensura;
|
namespace QWERTYkez.Mensura;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal class Mimics<T>
|
internal class ListMimic<T>
|
||||||
{
|
{
|
||||||
public T[] Items = null!;
|
public T[] Items = null!;
|
||||||
public int Size;
|
public int Size;
|
||||||
public int Version;
|
public int Version;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Explicit, Size = 16)]
|
||||||
internal struct NullableDoubleMimic
|
public struct NullableDoubleMimic
|
||||||
{
|
{
|
||||||
public double Value;
|
[FieldOffset(0)] public bool HasValue;
|
||||||
public byte HasValue;
|
[FieldOffset(8)] public double Value;
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,6 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
|
||||||
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
|
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<NoWarn>1701;1702;IDE1006</NoWarn>
|
<NoWarn>1701;1702;IDE1006</NoWarn>
|
||||||
@@ -13,8 +12,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" PrivateAssets="All" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" PrivateAssets="All" />
|
||||||
|
<ProjectReference Include="..\QWERTYkez.Mensura.Generator\QWERTYkez.Mensura.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||||
<ProjectReference Include="..\QWERTYkez.Mensura.Generator\QWERTYkez.Mensura.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
<InternalsVisibleTo Include="QWERTYkez.Mensura.Tests" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -61,21 +61,21 @@ public static class AreaSqrtExtension
|
|||||||
{
|
{
|
||||||
// === ReadOnlySpan
|
// === ReadOnlySpan
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt(
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt(
|
||||||
this ReadOnlySpan<Area> units, Span<Length> destination) => units.Sqrt3<Area, Length>(destination);
|
this ReadOnlySpan<Area> units, Span<Length> destination) => units.Cbrt<Area, Length>(destination);
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt(
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt(
|
||||||
this ReadOnlySpan<Area?> units, Span<Length?> destination) => units.Sqrt3<Area, Length>(destination);
|
this ReadOnlySpan<Area?> units, Span<Length?> destination) => units.Cbrt<Area, Length>(destination);
|
||||||
|
|
||||||
// === Array ===
|
// === Array ===
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static Length[] Sqrt(this Area[] units) => units.Sqrt3<Area, Length>();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]public static Length[] Sqrt(this Area[] units) => units.Cbrt<Area, Length>();
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Sqrt(this Area?[] units) => units.Sqrt3<Area, Length>();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Sqrt(this Area?[] units) => units.Cbrt<Area, Length>();
|
||||||
|
|
||||||
// === List<T> ===
|
// === List<T> ===
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Sqrt(this List<Area> units) => units.Sqrt3<Area, Length>();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Sqrt(this List<Area> units) => units.Cbrt<Area, Length>();
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Sqrt(this List<Area?> units) => units.Sqrt3<Area, Length>();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Sqrt(this List<Area?> units) => units.Cbrt<Area, Length>();
|
||||||
|
|
||||||
// === IEnumerable<T> ===
|
// === IEnumerable<T> ===
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Sqrt(this IEnumerable<Area> units) => units.Sqrt3<Area, Length>();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Sqrt(this IEnumerable<Area> units) => units.Cbrt<Area, Length>();
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Sqrt(this IEnumerable<Area?> units) => units.Sqrt3<Area, Length>();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Sqrt(this IEnumerable<Area?> units) => units.Cbrt<Area, Length>();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal readonly struct AreaConv
|
internal readonly struct AreaConv
|
||||||
|
|||||||
@@ -38,22 +38,22 @@ public readonly partial record struct Volume
|
|||||||
public static class VolumeSqrtExtension
|
public static class VolumeSqrtExtension
|
||||||
{
|
{
|
||||||
// === ReadOnlySpan
|
// === ReadOnlySpan
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt3(
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Cbrt(
|
||||||
this ReadOnlySpan<Volume> units, Span<Length> destination) => units.Sqrt3<Volume, Length>(destination);
|
this ReadOnlySpan<Volume> units, Span<Length> destination) => units.Cbrt<Volume, Length>(destination);
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Sqrt3(
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Cbrt(
|
||||||
this ReadOnlySpan<Volume?> units, Span<Length?> destination) => units.Sqrt3<Volume, Length>(destination);
|
this ReadOnlySpan<Volume?> units, Span<Length?> destination) => units.Cbrt<Volume, Length>(destination);
|
||||||
|
|
||||||
// === Array ===
|
// === Array ===
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length[] Sqrt3(this Volume[] units) => units.Sqrt3<Volume, Length>();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length[] Cbrt(this Volume[] units) => units.Cbrt<Volume, Length>();
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Sqrt3(this Volume?[] units) => units.Sqrt3<Volume, Length>();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Length?[] Cbrt(this Volume?[] units) => units.Cbrt<Volume, Length>();
|
||||||
|
|
||||||
// === List<T> ===
|
// === List<T> ===
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Sqrt3(this List<Volume> units) => units.Sqrt3<Volume, Length>();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length> Cbrt(this List<Volume> units) => units.Cbrt<Volume, Length>();
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Sqrt3(this List<Volume?> units) => units.Sqrt3<Volume, Length>();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static List<Length?> Cbrt(this List<Volume?> units) => units.Cbrt<Volume, Length>();
|
||||||
|
|
||||||
// === IEnumerable<T> ===
|
// === IEnumerable<T> ===
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Sqrt3(this IEnumerable<Volume> units) => units.Sqrt3<Volume, Length>();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length> Cbrt(this IEnumerable<Volume> units) => units.Cbrt<Volume, Length>();
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Sqrt3(this IEnumerable<Volume?> units) => units.Sqrt3<Volume, Length>();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static IEnumerable<Length?> Cbrt(this IEnumerable<Volume?> units) => units.Cbrt<Volume, Length>();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal readonly struct VolumeConv
|
internal readonly struct VolumeConv
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,70 +1,70 @@
|
|||||||
//#if DEBUG
|
#if DEBUG
|
||||||
//namespace QWERTYkez.Mensura.Units;
|
namespace QWERTYkez.Mensura.Units;
|
||||||
|
|
||||||
///// <summary>
|
/// <summary>
|
||||||
///// Base value is MilliMeters
|
/// Base value is MilliMeters
|
||||||
///// </summary>
|
/// </summary>
|
||||||
//[DebuggerDisplay("mm = {_MilliMeters.ToString(\"0.###\")}, m = {Meters.ToString(\"0.###\")}")]
|
[DebuggerDisplay("mm = {_MilliMeters.ToString(\"0.###\")}, m = {Meters.ToString(\"0.###\")}")]
|
||||||
//public readonly partial record struct XXXXXXXX
|
public readonly partial record struct XXXXXXXX
|
||||||
//{
|
{
|
||||||
// public static XXXXXXXX MilliMeter { get; } = new(1);
|
public static XXXXXXXX MilliMeter { get; } = new(1);
|
||||||
// [NotMapped, JsonIgnore, IgnoreDataMember] public double _MilliMeters { get => _Value; init => _Value = value; }
|
[NotMapped, JsonIgnore, IgnoreDataMember] public double _MilliMeters { get => _Value; init => _Value = value; }
|
||||||
|
|
||||||
|
|
||||||
// public static XXXXXXXX CentiMeter { get; } = new(XXXXXXXXConv.CentiMeters.To(1));
|
public static XXXXXXXX CentiMeter { get; } = new(XXXXXXXXConv.CentiMeters.To(1));
|
||||||
// [NotMapped, JsonIgnore, IgnoreDataMember]
|
[NotMapped, JsonIgnore, IgnoreDataMember]
|
||||||
// public double CentiMeters
|
public double CentiMeters
|
||||||
// {
|
{
|
||||||
// get => XXXXXXXXConv.CentiMeters.From(_Value);
|
get => XXXXXXXXConv.CentiMeters.From(_Value);
|
||||||
// init
|
init
|
||||||
// {
|
{
|
||||||
// _Value = XXXXXXXXConv.CentiMeters.To(value);
|
_Value = XXXXXXXXConv.CentiMeters.To(value);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// public static XXXXXXXX DeciMeter { get; } = new(XXXXXXXXConv.DeciMeters.To(1));
|
public static XXXXXXXX DeciMeter { get; } = new(XXXXXXXXConv.DeciMeters.To(1));
|
||||||
// [NotMapped, JsonIgnore, IgnoreDataMember]
|
[NotMapped, JsonIgnore, IgnoreDataMember]
|
||||||
// public double DeciMeters
|
public double DeciMeters
|
||||||
// {
|
{
|
||||||
// get => XXXXXXXXConv.DeciMeters.From(_Value);
|
get => XXXXXXXXConv.DeciMeters.From(_Value);
|
||||||
// init => _Value = XXXXXXXXConv.DeciMeters.To(value);
|
init => _Value = XXXXXXXXConv.DeciMeters.To(value);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// public static XXXXXXXX Meter { get; } = new(XXXXXXXXConv.Meters.To(1));
|
public static XXXXXXXX Meter { get; } = new(XXXXXXXXConv.Meters.To(1));
|
||||||
// [NotMapped, JsonIgnore, IgnoreDataMember]
|
[NotMapped, JsonIgnore, IgnoreDataMember]
|
||||||
// public double Meters
|
public double Meters
|
||||||
// {
|
{
|
||||||
// get => XXXXXXXXConv.Meters.From(_Value);
|
get => XXXXXXXXConv.Meters.From(_Value);
|
||||||
// init => _Value = XXXXXXXXConv.Meters.To(value);
|
init => _Value = XXXXXXXXConv.Meters.To(value);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// public static XXXXXXXX KiloMeter { get; } = new(XXXXXXXXConv.KiloMeters.To(1));
|
public static XXXXXXXX KiloMeter { get; } = new(XXXXXXXXConv.KiloMeters.To(1));
|
||||||
// [NotMapped, JsonIgnore, IgnoreDataMember]
|
[NotMapped, JsonIgnore, IgnoreDataMember]
|
||||||
// public double KiloMeters
|
public double KiloMeters
|
||||||
// {
|
{
|
||||||
// get => XXXXXXXXConv.KiloMeters.From(_Value);
|
get => XXXXXXXXConv.KiloMeters.From(_Value);
|
||||||
// init => _Value = XXXXXXXXConv.KiloMeters.To(value);
|
init => _Value = XXXXXXXXConv.KiloMeters.To(value);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
|
||||||
// public XXXXXXXX AddMilliMeters(double value) => new(_Value + value);
|
public XXXXXXXX AddMilliMeters(double value) => new(_Value + value);
|
||||||
// public XXXXXXXX AddCentiMeters(double value) => new(_Value + XXXXXXXXConv.CentiMeters.To(value));
|
public XXXXXXXX AddCentiMeters(double value) => new(_Value + XXXXXXXXConv.CentiMeters.To(value));
|
||||||
// public XXXXXXXX AddDeciMeters(double value) => new(_Value + XXXXXXXXConv.DeciMeters.To(value));
|
public XXXXXXXX AddDeciMeters(double value) => new(_Value + XXXXXXXXConv.DeciMeters.To(value));
|
||||||
// public XXXXXXXX AddMeters(double value) => new(_Value + XXXXXXXXConv.Meters.To(value));
|
public XXXXXXXX AddMeters(double value) => new(_Value + XXXXXXXXConv.Meters.To(value));
|
||||||
// public XXXXXXXX AddKiloMeters(double value) => new(_Value + XXXXXXXXConv.KiloMeters.To(value));
|
public XXXXXXXX AddKiloMeters(double value) => new(_Value + XXXXXXXXConv.KiloMeters.To(value));
|
||||||
//}
|
}
|
||||||
|
|
||||||
|
|
||||||
//internal readonly struct XXXXXXXXConv
|
internal readonly struct XXXXXXXXConv
|
||||||
//{
|
{
|
||||||
// private XXXXXXXXConv(double multiplicator) => this.Multiplicator = multiplicator;
|
private XXXXXXXXConv(double multiplicator) => this.Multiplicator = multiplicator;
|
||||||
// public double To(double value) => value * Multiplicator;
|
public double To(double value) => value * Multiplicator;
|
||||||
// public double From(double value) => value / Multiplicator;
|
public double From(double value) => value / Multiplicator;
|
||||||
// public double Multiplicator { get; init; }
|
public double Multiplicator { get; init; }
|
||||||
// public static XXXXXXXXConv MilliMeters { get; } = new(1);
|
public static XXXXXXXXConv MilliMeters { get; } = new(1);
|
||||||
// public static XXXXXXXXConv CentiMeters { get; } = new(10);
|
public static XXXXXXXXConv CentiMeters { get; } = new(10);
|
||||||
// public static XXXXXXXXConv DeciMeters { get; } = new(100);
|
public static XXXXXXXXConv DeciMeters { get; } = new(100);
|
||||||
// public static XXXXXXXXConv Meters { get; } = new(1000);
|
public static XXXXXXXXConv Meters { get; } = new(1000);
|
||||||
// public static XXXXXXXXConv KiloMeters { get; } = new(1000000);
|
public static XXXXXXXXConv KiloMeters { get; } = new(1000000);
|
||||||
//}
|
}
|
||||||
//#endif
|
#endif
|
||||||
Reference in New Issue
Block a user