Merge branch 'master' of https://lancool.qwertykez.fun/QWERTYkez/QWERTYkez.Mensura
All checks were successful
Publish NuGet packages / publish (push) Successful in 1m1s

This commit is contained in:
melekhin
2026-06-15 08:39:01 +07:00
35 changed files with 2736 additions and 2189 deletions

View File

@@ -0,0 +1,36 @@
name: Publish NuGet packages
on:
push:
tags:
- 'v*'
jobs:
publish:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'
- name: Get version from tag
shell: pwsh
run: |
$tag = "$env:GITHUB_REF_NAME"
$version = $tag -replace '^v', ''
echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- name: Pack Mensura
run: dotnet pack QWERTYkez.Mensura/QWERTYkez.Mensura.csproj -c Release -o ./packages -p:Version=${{ env.VERSION }}
- name: Push to Gitea
shell: pwsh
run: |
Get-ChildItem -Path ./packages -Filter *.nupkg | ForEach-Object {
dotnet nuget push $_.FullName --source https://lancool.qwertykez.fun/api/packages/QWERTYkez/nuget --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate
}

201
LICENSE.txt Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -81,6 +81,24 @@ namespace QWERTYkez.Mensura
sb.AppendLine("}");
spc.AddSource(".ComplexUnits.MensuraBinder.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
sb = new StringBuilder();
sb.AppendLine("using Microsoft.EntityFrameworkCore;");
sb.AppendLine("namespace QWERTYkez.Mensura.Extensions;");
sb.AppendLine("public static partial class EFCoreExtension");
sb.AppendLine("{");
sb.AppendLine(" [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]");
sb.AppendLine(" internal static void AddGeneratedComplexConverters(ModelConfigurationBuilder configurationBuilder)");
sb.AppendLine(" {");
foreach (var structInfo in structs)
{
sb.AppendLine($" configurationBuilder.Properties<{structInfo.TypeName}>().HaveConversion<MensuraUnitConverter<{structInfo.TypeName}>>();");
}
sb.AppendLine(" }");
sb.AppendLine("}");
spc.AddSource(".ComplexUnits.EFCoreExtension.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
}
});
}
@@ -1254,15 +1272,6 @@ public readonly partial record struct {typeNameZ} : IMensuraUnit<{typeNameZ}>, I
public static class {typeNameZ}Extensions
{
internal static double Protected(this {typeNameZ}? unit) => unit is null ? 0d : unit.Value._Value;
internal static {typeNameZ} ProtectedU(this {typeNameZ}? unit) => unit is null ? {typeNameZ}.Zero : unit.Value;
internal static double ToDouble(this {typeNameB}? unit) => unit?._Value ?? 0d;
// === ReadOnlySpan
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Div(this ReadOnlySpan<{typeNameZ}> units,
double divisor, Span<{typeNameZ}> destination) => units.Div<{typeNameZ}>(divisor, destination);

View File

@@ -67,6 +67,24 @@ namespace QWERTYkez.Mensura
sb.AppendLine("}");
spc.AddSource(".Units.MensuraBinder.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
sb = new StringBuilder();
sb.AppendLine("using Microsoft.EntityFrameworkCore;");
sb.AppendLine("namespace QWERTYkez.Mensura.Extensions;");
sb.AppendLine("public static partial class EFCoreExtension");
sb.AppendLine("{");
sb.AppendLine(" [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]");
sb.AppendLine(" internal static void AddGeneratedConverters(ModelConfigurationBuilder configurationBuilder)");
sb.AppendLine(" {");
foreach (var structInfo in structs)
{
sb.AppendLine($" configurationBuilder.Properties<{structInfo.TypeName}>().HaveConversion<MensuraUnitConverter<{structInfo.TypeName}>>();");
}
sb.AppendLine(" }");
sb.AppendLine("}");
spc.AddSource(".Units.EFCoreExtension.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
}
});
}
@@ -1073,14 +1091,6 @@ public readonly partial record struct {typeName} : IMensuraUnit<{typeName}>, IEq
public static class {typeName}Extensions
{
internal static double Protected(this {typeName}? unit) => unit is null ? 0d : unit.Value._Value;
internal static {typeName} ProtectedU(this {typeName}? unit) => unit is null ? {typeName}.Zero : unit.Value;
// === ReadOnlySpan
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Div(this ReadOnlySpan<{typeName}> units,
double divisor, Span<{typeName}> destination) => units.Div<{typeName}>(divisor, destination);

View File

@@ -2,7 +2,7 @@
namespace QWERTYkez.Mensura.Tests;
public class AggregateUnitExtensions
public class AggregateUnitExtensionsTest
{
// Вспомогательный метод для создания объекта Length.
// Если у вас используется фабричный метод (например, Length.FromMeters), замените код внутри.

View File

@@ -1,6 +1,6 @@
namespace QWERTYkez.Mensura.Tests;
public class CastExtensions
public class CastExtensionsTest
{
private const double NormalValue1 = 42.42;
private const double NormalValue2 = 100.05;

View File

@@ -1,6 +1,6 @@
namespace QWERTYkez.Mensura.Tests
{
public class CollectionsDivideExtensionsTests
public class CollectionsDivideExtensionsTest
{
private const double Tolerance = 1e-12;
private static readonly Length scalarUnit = Length.Meter; // 1000 mm
@@ -31,7 +31,7 @@
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(0 / 2.0, (double)result[1]!, Tolerance);
Assert.Equal(1 / 2.0, (double)result[2]!, Tolerance);
}
@@ -52,7 +52,7 @@
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 / 0, (double)result[1]!, Tolerance);
Assert.Equal(2.0 / 1, (double)result[2]!, Tolerance);
}
@@ -73,7 +73,7 @@
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(0 / 2.0, (double)result[1]!, Tolerance);
Assert.Equal(1 / 2.0, (double)result[2]!, Tolerance);
}
@@ -94,7 +94,7 @@
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 / 0, (double)result[1]!, Tolerance);
Assert.Equal(2.0 / 1, (double)result[2]!, Tolerance);
}
@@ -115,7 +115,7 @@
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(0 / 2.0, (double)dest[1]!, Tolerance);
Assert.Equal(1 / 2.0, (double)dest[2]!, Tolerance);
}
@@ -136,7 +136,7 @@
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 / 0, (double)dest[1]!, Tolerance);
Assert.Equal(2.0 / 1, (double)dest[2]!, Tolerance);
}
@@ -157,7 +157,7 @@
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(0 / 2.0, (double)result[1]!, Tolerance);
Assert.Equal(1 / 2.0, (double)result[2]!, Tolerance);
}
@@ -178,7 +178,7 @@
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 / 0, (double)result[1]!, Tolerance);
Assert.Equal(2.0 / 1, (double)result[2]!, Tolerance);
}
@@ -199,7 +199,7 @@
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(0 / 1000, (double)result[1]!, Tolerance);
Assert.Equal(3.0 / 1000, (double)result[2]!, Tolerance);
}
@@ -220,7 +220,7 @@
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 / 0.0, (double)result[1]!, Tolerance);
Assert.Equal(1000 / 3.0, (double)result[2]!, Tolerance);
}
@@ -243,7 +243,7 @@
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(0 / 1000, (double)result[1]!, Tolerance);
Assert.Equal(3.0 / 1000, (double)result[2]!, Tolerance);
}
@@ -266,7 +266,7 @@
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 / 0.0, (double)result[1]!, Tolerance);
Assert.Equal(1000 / 3.0, (double)result[2]!, Tolerance);
}

View File

@@ -1,6 +1,6 @@
namespace QWERTYkez.Mensura.Tests
{
public class CollectionsMinusExtensionsTests
public class CollectionsMinusExtensionsTest
{
private const double Tolerance = 1e-12;
private static readonly Length scalarUnit = Length.Meter; // 1000 mm
@@ -44,7 +44,7 @@
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(0 - 1000, (double)result[1]!, Tolerance);
Assert.Equal(1 - 1000, (double)result[2]!, Tolerance);
}
@@ -65,7 +65,7 @@
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 - 0, (double)result[1]!, Tolerance);
Assert.Equal(1000 - 1, (double)result[2]!, Tolerance);
}
@@ -86,7 +86,7 @@
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(0 - 1000, (double)result[1]!, Tolerance);
Assert.Equal(1 - 1000, (double)result[2]!, Tolerance);
}
@@ -107,7 +107,7 @@
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 - 0, (double)result[1]!, Tolerance);
Assert.Equal(1000 - 1, (double)result[2]!, Tolerance);
}
@@ -128,7 +128,7 @@
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(0 - 1000, (double)dest[1]!, Tolerance);
Assert.Equal(1 - 1000, (double)dest[2]!, Tolerance);
}
@@ -149,7 +149,7 @@
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 - 0, (double)dest[1]!, Tolerance);
Assert.Equal(1000 - 1, (double)dest[2]!, Tolerance);
}
@@ -170,7 +170,7 @@
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(0 - 1000, (double)result[1]!, Tolerance);
Assert.Equal(1 - 1000, (double)result[2]!, Tolerance);
}
@@ -191,7 +191,7 @@
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 - 0, (double)result[1]!, Tolerance);
Assert.Equal(1000 - 1, (double)result[2]!, Tolerance);
}
@@ -212,7 +212,7 @@
var result = nullableDoubleArray.Minus(scalarUnit);
Assert.Equal(3, result.Length);
Assert.Equal(500 - 1000, (double)result[0]!, Tolerance);
Assert.Null(result[1]);
Assert.Equal(0 - 1000, (double)result[1]!, Tolerance);
Assert.Equal(200 - 1000, (double)result[2]!, Tolerance);
}
@@ -233,7 +233,7 @@
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 - 0, (double)result[1]!, Tolerance);
Assert.Equal(1000 - 200, (double)result[2]!, Tolerance);
}
@@ -254,7 +254,7 @@
var result = nullableDoubleList.Minus(scalarUnit);
Assert.Equal(3, result.Count);
Assert.Equal(500 - 1000, (double)result[0]!, Tolerance);
Assert.Null(result[1]);
Assert.Equal(0 - 1000, (double)result[1]!, Tolerance);
Assert.Equal(200 - 1000, (double)result[2]!, Tolerance);
}
@@ -275,7 +275,7 @@
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 - 0, (double)result[1]!, Tolerance);
Assert.Equal(1000 - 200, (double)result[2]!, Tolerance);
}

View File

@@ -1,6 +1,6 @@
namespace QWERTYkez.Mensura.Tests
{
public class CollectionsMultiplyExtensionsTests
public class CollectionsMultiplyExtensionsTest
{
private const double Tolerance = 1e-12;
private static readonly Length scalarUnit = Length.Meter; // 1000 mm
@@ -43,7 +43,7 @@
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(0, (double)result[1]!, Tolerance);
Assert.Equal(1 * 2, (double)result[2]!, Tolerance);
}
@@ -64,7 +64,7 @@
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(0, (double)result[1]!, Tolerance);
Assert.Equal(2 * 1, (double)result[2]!, Tolerance);
}
@@ -85,7 +85,7 @@
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(0, (double)result[1]!, Tolerance);
Assert.Equal(1 * 2, (double)result[2]!, Tolerance);
}
@@ -106,7 +106,7 @@
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(0, (double)result[1]!, Tolerance);
Assert.Equal(2 * 1, (double)result[2]!, Tolerance);
}
@@ -127,7 +127,7 @@
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(0, (double)dest[1]!, Tolerance);
Assert.Equal(1 * 2, (double)dest[2]!, Tolerance);
}
@@ -148,7 +148,7 @@
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(0, (double)dest[1]!, Tolerance);
Assert.Equal(2 * 1, (double)dest[2]!, Tolerance);
}
@@ -169,7 +169,7 @@
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(0, (double)result[1]!, Tolerance);
Assert.Equal(1 * 2, (double)result[2]!, Tolerance);
}
@@ -190,7 +190,7 @@
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(0, (double)result[1]!, Tolerance);
Assert.Equal(2 * 1, (double)result[2]!, Tolerance);
}
@@ -211,7 +211,7 @@
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(0, (double)result[1]!, Tolerance);
Assert.Equal(3 * 1000, (double)result[2]!, Tolerance);
}
@@ -232,7 +232,7 @@
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(0, (double)result[1]!, Tolerance);
Assert.Equal(1000 * 3, (double)result[2]!, Tolerance);
}
@@ -253,7 +253,7 @@
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(0, (double)result[1]!, Tolerance);
Assert.Equal(3 * 1000, (double)result[2]!, Tolerance);
}
@@ -274,7 +274,7 @@
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(0, (double)result[1]!, Tolerance);
Assert.Equal(1000 * 3, (double)result[2]!, Tolerance);
}

View File

@@ -1,29 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using QWERTYkez.Mensura.Units;
using QWERTYkez.Mensura.Extensions;
using Xunit;
namespace QWERTYkez.Mensura.Tests
namespace QWERTYkez.Mensura.Tests
{
public class CollectionsPlusExtensionsTests
public class CollectionsPlusExtensionsTest
{
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 };
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 = 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 };
private static readonly double[] doubleArray = [200.0, 300.0];
private static readonly double?[] nullableDoubleArray = [200.0, null, 300.0];
private static readonly List<double> doubleList = [200.0, 300.0];
private static readonly List<double?> nullableDoubleList = [200.0, null, 300.0];
// ====================== 1. T[] + double ======================
[Fact]
@@ -42,7 +35,7 @@ namespace QWERTYkez.Mensura.Tests
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(0 + 500, (double)result[1]!, Tolerance);
Assert.Equal(1 + 500, (double)result[2]!, Tolerance);
}
@@ -63,7 +56,7 @@ namespace QWERTYkez.Mensura.Tests
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 + 0, (double)result[1]!, Tolerance);
Assert.Equal(500 + 1, (double)result[2]!, Tolerance);
}
@@ -84,7 +77,7 @@ namespace QWERTYkez.Mensura.Tests
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(0 + 500, (double)result[1]!, Tolerance);
Assert.Equal(1 + 500, (double)result[2]!, Tolerance);
}
@@ -105,7 +98,7 @@ namespace QWERTYkez.Mensura.Tests
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 + 0, (double)result[1]!, Tolerance);
Assert.Equal(500 + 1, (double)result[2]!, Tolerance);
}
@@ -126,7 +119,7 @@ namespace QWERTYkez.Mensura.Tests
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(0 + 500, (double)dest[1]!, Tolerance);
Assert.Equal(1 + 500, (double)dest[2]!, Tolerance);
}
@@ -147,7 +140,7 @@ namespace QWERTYkez.Mensura.Tests
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 + 0, (double)dest[1]!, Tolerance);
Assert.Equal(500 + 1, (double)dest[2]!, Tolerance);
}
@@ -168,7 +161,7 @@ namespace QWERTYkez.Mensura.Tests
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(0 + 500, (double)result[1]!, Tolerance);
Assert.Equal(1 + 500, (double)result[2]!, Tolerance);
}
@@ -189,7 +182,7 @@ namespace QWERTYkez.Mensura.Tests
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 + 0, (double)result[1]!, Tolerance);
Assert.Equal(500 + 1, (double)result[2]!, Tolerance);
}
@@ -210,7 +203,7 @@ namespace QWERTYkez.Mensura.Tests
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(0 + 1000, (double)result[1]!, Tolerance);
Assert.Equal(300 + 1000, (double)result[2]!, Tolerance);
}
@@ -231,7 +224,7 @@ namespace QWERTYkez.Mensura.Tests
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 + 0, (double)result[1]!, Tolerance);
Assert.Equal(1000 + 300, (double)result[2]!, Tolerance);
}
@@ -252,7 +245,7 @@ namespace QWERTYkez.Mensura.Tests
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(0 + 1000, (double)result[1]!, Tolerance);
Assert.Equal(300 + 1000, (double)result[2]!, Tolerance);
}
@@ -273,7 +266,7 @@ namespace QWERTYkez.Mensura.Tests
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 + 0, (double)result[1]!, Tolerance);
Assert.Equal(1000 + 300, (double)result[2]!, Tolerance);
}
@@ -310,7 +303,7 @@ namespace QWERTYkez.Mensura.Tests
[Fact]
public void Plus_NullArray_ReturnsNull()
{
Length[] nullArray = null;
Length[] nullArray = null!;
var result = nullArray.Plus<Length>(5.0);
Assert.Null(result);
}
@@ -318,7 +311,7 @@ namespace QWERTYkez.Mensura.Tests
[Fact]
public void Plus_NullList_ReturnsNull()
{
List<Length> nullList = null;
List<Length> nullList = null!;
var result = nullList.Plus<Length>(5.0);
Assert.Null(result);
}

View File

@@ -1,6 +1,6 @@
namespace QWERTYkez.Mensura.Tests;
public class CollectionsPow2Extensions
public class CollectionsPow2ExtensionsTest
{
[Fact]
public void Pow2_Array_CalculatesCorrectly()

View File

@@ -1,6 +1,6 @@
namespace QWERTYkez.Mensura.Tests;
public class Pow3ExtensionsTests
public class CollectionsPow3ExtensionsTest
{
[Fact]
public void Pow3_Array_CalculatesCorrectly()

View File

@@ -1,6 +1,6 @@
namespace QWERTYkez.Mensura.Tests;
public class CollectionsPowNExtensions
public class CollectionsPowNExtensionsTest
{
private const double BaseVal = 3.0;
private const double Expected = 9.0; // 3^2 = 9

View File

@@ -1,6 +1,6 @@
namespace QWERTYkez.Mensura.Tests;
public class CollectionsRootOfCubeExtensions
public class CollectionsRootOfCubeExtensionsTest
{
[Fact]
public void Cbrt_Array_CalculatesCorrectly()
@@ -23,7 +23,7 @@ public class CollectionsRootOfCubeExtensions
var result = source.Cbrt<Length, Length>();
Assert.Equal(4, result[0]?._Value);
Assert.Null(result[1]);
Assert.Equal(0, result[1]?._Value);
Assert.Equal(6, result[2]?._Value);
}

View File

@@ -1,6 +1,6 @@
namespace QWERTYkez.Mensura.Tests;
public class CollectionsRootOfSquareExtensions
public class CollectionsRootOfSquareExtensionsTest
{
[Fact]
public void Sqrt_Array_ShouldCalculateCorrectly()
@@ -28,7 +28,7 @@ public class CollectionsRootOfSquareExtensions
// Assert
Assert.Equal(5, result[0]?._Value);
Assert.Null(result[1]);
Assert.Equal(0, result[1]?._Value);
Assert.Equal(10, result[2]?._Value);
}

View File

@@ -1,164 +0,0 @@
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
}

View File

@@ -0,0 +1,394 @@
using System;
using System.Collections.Generic;
using System.Linq;
using QWERTYkez.Mensura.Extensions;
using Xunit;
namespace QWERTYkez.Mensura.Tests
{
public class DoubleExtensionsTests
{
private const double Tolerance = 1e-12;
#region Single value conversions (non-nullable)
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(255)]
public void ToDouble_Byte_ReturnsExpected(byte value) => Assert.Equal(value, value.ToDouble());
[Theory]
[InlineData(-128)]
[InlineData(0)]
[InlineData(127)]
public void ToDouble_SByte_ReturnsExpected(sbyte value) => Assert.Equal(value, value.ToDouble());
[Theory]
[InlineData(-32768)]
[InlineData(0)]
[InlineData(32767)]
public void ToDouble_Short_ReturnsExpected(short value) => Assert.Equal(value, value.ToDouble());
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(65535)]
public void ToDouble_UShort_ReturnsExpected(ushort value) => Assert.Equal(value, value.ToDouble());
[Theory]
[InlineData(-2147483648)]
[InlineData(0)]
[InlineData(2147483647)]
public void ToDouble_Int_ReturnsExpected(int value) => Assert.Equal(value, value.ToDouble());
[Theory]
[InlineData(0U)]
[InlineData(1U)]
[InlineData(uint.MaxValue)]
public void ToDouble_UInt_ReturnsExpected(uint value) => Assert.Equal(value, value.ToDouble());
[Theory]
[InlineData(-9223372036854775808)]
[InlineData(0)]
[InlineData(9223372036854775807)]
public void ToDouble_Long_ReturnsExpected(long value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
[Theory]
[InlineData(0UL)]
[InlineData(1UL)]
[InlineData(ulong.MaxValue)]
public void ToDouble_ULong_ReturnsExpected(ulong value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
[Theory]
[InlineData(-123456789)]
[InlineData(0)]
[InlineData(123456789)]
public void ToDouble_NInt_ReturnsExpected(nint value) => Assert.Equal(value, value.ToDouble());
[Theory]
[InlineData(0u)]
[InlineData(123456789u)]
public void ToDouble_NUInt_ReturnsExpected(nuint value) => Assert.Equal((double)value, value.ToDouble());
[Theory]
[InlineData(0.0f)]
[InlineData(123.456f)]
[InlineData(-987.654f)]
[InlineData(float.Epsilon)]
[InlineData(float.MaxValue)]
public void ToDouble_Float_ReturnsExpected(float value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
[Theory]
[InlineData(0.0)]
[InlineData(123.456)]
[InlineData(-987.654)]
public void ToDouble_Decimal_ReturnsExpected(decimal value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
[Theory]
[InlineData(0.0)]
[InlineData(123.456)]
[InlineData(-987.654)]
public void ToDouble_Half_ReturnsExpected(Half value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
#endregion
#region Single value conversions (nullable)
[Fact]
public void ToDouble_NullableByte_Null_ReturnsZero() => Assert.Equal(0.0, ((byte?)null).ToDouble());
[Fact]
public void ToDouble_NullableSByte_Null_ReturnsZero() => Assert.Equal(0.0, ((sbyte?)null).ToDouble());
[Fact]
public void ToDouble_NullableShort_Null_ReturnsZero() => Assert.Equal(0.0, ((short?)null).ToDouble());
[Fact]
public void ToDouble_NullableUShort_Null_ReturnsZero() => Assert.Equal(0.0, ((ushort?)null).ToDouble());
[Fact]
public void ToDouble_NullableInt_Null_ReturnsZero() => Assert.Equal(0.0, ((int?)null).ToDouble());
[Fact]
public void ToDouble_NullableUInt_Null_ReturnsZero() => Assert.Equal(0.0, ((uint?)null).ToDouble());
[Fact]
public void ToDouble_NullableLong_Null_ReturnsZero() => Assert.Equal(0.0, ((long?)null).ToDouble());
[Fact]
public void ToDouble_NullableULong_Null_ReturnsZero() => Assert.Equal(0.0, ((ulong?)null).ToDouble());
[Fact]
public void ToDouble_NullableNInt_Null_ReturnsZero() => Assert.Equal(0.0, ((nint?)null).ToDouble());
[Fact]
public void ToDouble_NullableNUInt_Null_ReturnsZero() => Assert.Equal(0.0, ((nuint?)null).ToDouble());
[Fact]
public void ToDouble_NullableFloat_Null_ReturnsZero() => Assert.Equal(0.0, ((float?)null).ToDouble());
[Fact]
public void ToDouble_NullableDecimal_Null_ReturnsZero() => Assert.Equal(0.0, ((decimal?)null).ToDouble());
[Fact]
public void ToDouble_NullableHalf_Null_ReturnsZero() => Assert.Equal(0.0, ((Half?)null).ToDouble());
#endregion
#region NET7_0_OR_GREATER
#if NET7_0_OR_GREATER
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(-1)]
[InlineData(long.MaxValue)]
public void ToDouble_Int128_ReturnsExpected(Int128 value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(ulong.MaxValue)]
public void ToDouble_UInt128_ReturnsExpected(UInt128 value) => Assert.Equal((double)value, value.ToDouble(), Tolerance);
[Fact]
public void ToDouble_NullableInt128_Null_ReturnsZero() => Assert.Equal(0.0, ((Int128?)null).ToDouble());
[Fact]
public void ToDouble_NullableUInt128_Null_ReturnsZero() => Assert.Equal(0.0, ((UInt128?)null).ToDouble());
#endif
#endregion
#region IEnumerable<T> -> IEnumerable<double> (non-nullable)
[Fact]
public void ToDouble_IEnumerableByte_ReturnsCorrect()
{
byte[] source = [1, 2, 3];
var result = source.ToDouble();
Assert.Equal(new double[] { 1, 2, 3 }, result);
}
[Fact]
public void ToDouble_IEnumerableByte_Empty_ReturnsEmpty()
{
var source = Array.Empty<byte>();
var result = source.ToDouble();
Assert.Empty(result);
}
[Fact]
public void ToDouble_IEnumerableByte_Null_Throws() => Assert.Null(((IEnumerable<byte>)null!).ToDouble());
[Fact]
public void ToDouble_IEnumerableInt_ReturnsCorrect()
{
int[] source = [-5, 0, 10];
var result = source.ToDouble();
Assert.Equal(new double[] { -5, 0, 10 }, result);
}
[Fact]
public void ToDouble_IEnumerableInt_Null_Throws() => Assert.Null(((IEnumerable<int>)null!).ToDouble());
#endregion
#region IEnumerable<T?> -> IEnumerable<double?>
[Fact]
public void ToDouble_IEnumerableNullableInt_ReturnsCorrect()
{
int?[] source = [1, null, 3];
var result = source.ToDouble();
Assert.Equal(3, result.Length);
Assert.Equal(1.0, result.First());
Assert.Null(result.Skip(1).First());
Assert.Equal(3.0, result.Last());
}
[Fact]
public void ToDouble_IEnumerableNullableInt_Null_Throws() => Assert.Null(((IEnumerable<int?>)null!).ToDouble());
#endregion
#region Array and List conversions (non-nullable)
[Fact]
public void ToDouble_ByteArray_ReturnsDoubleArray()
{
byte[] arr = [10, 20];
var result = arr.ToDouble();
Assert.Equal(new double[] { 10, 20 }, result);
}
[Fact]
public void ToDouble_ByteArray_Null_ReturnsNull() => Assert.Null(((byte[])null!).ToDouble());
[Fact]
public void ToDouble_ByteList_ReturnsDoubleList()
{
var list = new List<byte> { 10, 20 };
var result = list.ToDouble();
Assert.Equal([10, 20], result);
}
[Fact]
public void ToDouble_ByteList_Null_ReturnsNull() => Assert.Null(((List<byte>)null!).ToDouble());
[Fact]
public void ToDouble_IntArray_ReturnsDoubleArray()
{
int[] arr = [-5, 0, 7];
var result = arr.ToDouble();
Assert.Equal(new double[] { -5, 0, 7 }, result);
}
[Fact]
public void ToDouble_IntList_ReturnsDoubleList()
{
var list = new List<int> { -5, 0, 7 };
var result = list.ToDouble();
Assert.Equal([-5, 0, 7], result);
}
#endregion
#region Array and List conversions (nullable)
[Fact]
public void ToDouble_NullableIntArray_ReturnsNullableDoubleArray()
{
int?[] arr = [1, null, 3];
var result = arr.ToDouble();
Assert.Equal(3, result.Length);
Assert.Equal(1.0, result[0]);
Assert.Null(result[1]);
Assert.Equal(3.0, result[2]);
}
[Fact]
public void ToDouble_NullableIntArray_Null_ReturnsNull() => Assert.Null(((int?[])null!).ToDouble());
[Fact]
public void ToDouble_NullableIntList_ReturnsNullableDoubleList()
{
var list = new List<int?> { 1, null, 3 };
var result = list.ToDouble();
Assert.Equal(3, result.Count);
Assert.Equal(1.0, result[0]);
Assert.Null(result[1]);
Assert.Equal(3.0, result[2]);
}
[Fact]
public void ToDouble_NullableIntList_Null_ReturnsNull() => Assert.Null(((List<int?>)null!).ToDouble());
#endregion
#region IReadOnlyCollection<T> -> Span<double>
[Fact]
public void ToDouble_IReadOnlyCollectionByte_Span_Works()
{
byte[] source = [1, 2];
Span<double> dest = new double[source.Length];
((IReadOnlyCollection<byte>)source).ToDouble(dest);
Assert.Equal(1.0, dest[0]);
Assert.Equal(2.0, dest[1]);
}
[Fact]
public void ToDouble_IReadOnlyCollectionByte_EmptySpan_Works()
{
byte[] source = [];
Span<double> dest = [];
((IReadOnlyCollection<byte>)source).ToDouble(dest);
}
[Fact]
public void ToDouble_IReadOnlyCollectionByte_DestinationTooShort_Throws()
{
byte[] source = [1, 2];
Assert.Throws<ArgumentException>(() =>
{
Span<double> dest = new double[1];
((IReadOnlyCollection<byte>)source).ToDouble(dest);
});
}
[Fact]
public void ToDouble_IReadOnlyCollectionNullableInt_Span_HandlesNulls()
{
int?[] source = [1, null, 3];
Span<double?> dest = new double?[3];
((IReadOnlyCollection<int?>)source).ToDouble(dest);
Assert.Equal(1.0, dest[0]);
Assert.Null(dest[1]);
Assert.Equal(3.0, dest[2]);
}
#endregion
#region Span conversions (ToDoubleCore) - через массивы
[Fact]
public void IntSpan_ToDouble_ConversionWorks()
{
int[] source = [1, 2, 3];
var result = source.ToDouble();
Assert.Equal(new double[] { 1, 2, 3 }, result);
}
[Fact]
public void FloatSpan_ToDouble_ConversionWorks()
{
float[] source = [1.1f, -2.2f];
var result = source.ToDouble();
Assert.Equal(1.1f, result[0], Tolerance);
Assert.Equal(-2.2f, result[1], Tolerance);
}
[Fact]
public void NullableDecimalSpan_ToDouble_HandlesNulls()
{
decimal?[] source = [1.5m, null, -3.3m];
var result = source.ToDouble();
Assert.Equal(3, result.Length);
Assert.Equal(1.5, result[0]!.Value, Tolerance);
Assert.Null(result[1]);
Assert.Equal(-3.3, result[2]!.Value, Tolerance);
}
#endregion
#region Edge cases
[Fact]
public void ToDouble_LongMaxValue_DoesNotOverflow()
{
long max = long.MaxValue;
double result = max.ToDouble();
Assert.Equal((double)max, result, Tolerance);
}
[Fact]
public void ToDouble_ULongMaxValue_DoesNotOverflow()
{
ulong max = ulong.MaxValue;
double result = max.ToDouble();
Assert.Equal((double)max, result, Tolerance);
}
[Fact]
public void ToDouble_Decimal_HighPrecision_DoesNotCrash()
{
decimal huge = decimal.MaxValue;
var result = huge.ToDouble();
Assert.False(double.IsInfinity(result));
}
#endregion
}
}

View File

@@ -20,6 +20,9 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="10.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
@@ -31,8 +34,6 @@
<ItemGroup>
<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" />
</ItemGroup>

View File

@@ -0,0 +1,98 @@
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
namespace QWERTYkez.Mensura.Tests
{
public class TestEntity1
{
public int Id { get; set; }
public Length Length { get; set; }
}
public class TestEntity2
{
public int Id { get; set; }
public double Length { get; set; }
}
public class SharedDbContext(DbContextOptions<SharedDbContext> options) : DbContext(options)
{
public DbSet<TestEntity1> Entities1 { get; set; }
public DbSet<TestEntity2> Entities2 { get; set; }
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.UseMensuraUnits();
}
}
public class IdentityConversionTest : IDisposable
{
private readonly SqliteConnection _connection;
public IdentityConversionTest()
{
_connection = new SqliteConnection("Filename=:memory:");
_connection.Open();
}
public void Dispose()
{
_connection?.Dispose();
GC.SuppressFinalize(this);
}
[Fact]
public void Length_And_Double_Are_Stored_Identically()
{
// 1. Сохраняем Length → читаем как double
double savedDoubleFromLength;
using (var context = new SharedDbContext(new DbContextOptionsBuilder<SharedDbContext>().UseSqlite(_connection).Options))
{
context.Database.EnsureCreated();
var expectedLength = Length.Meter; // 1000 мм
context.Entities1.Add(new TestEntity1 { Length = expectedLength });
context.SaveChanges();
using var cmd = context.Database.GetDbConnection().CreateCommand();
cmd.CommandText = "SELECT Length FROM Entities1";
savedDoubleFromLength = (double)cmd.ExecuteScalar()!;
}
// 2. Сохраняем double → читаем как Length
double savedDoubleFromDouble = 1234.5;
using (var context = new SharedDbContext(new DbContextOptionsBuilder<SharedDbContext>().UseSqlite(_connection).Options))
{
context.Database.EnsureCreated();
context.Entities2.Add(new TestEntity2 { Length = savedDoubleFromDouble });
context.SaveChanges();
using var cmd = context.Database.GetDbConnection().CreateCommand();
cmd.CommandText = "SELECT Length FROM Entities2";
savedDoubleFromDouble = (double)cmd.ExecuteScalar()!; // должно быть 1234.5
}
// 3. Проверяем, что сырые значения сохранены корректно
Assert.Equal(1000.0, savedDoubleFromLength);
Assert.Equal(1234.5, savedDoubleFromDouble);
// 4. Проверяем обратимость: читаем из Entities1 как TestEntity2
using (var context = new SharedDbContext(new DbContextOptionsBuilder<SharedDbContext>().UseSqlite(_connection).Options))
{
var fromLengthTable = context.Entities2
.FromSqlRaw("SELECT Id, Length FROM Entities1")
.First();
Assert.Equal(1000.0, fromLengthTable.Length);
}
// 5. Проверяем обратимость: читаем из Entities2 как TestEntity1
using (var context = new SharedDbContext(new DbContextOptionsBuilder<SharedDbContext>().UseSqlite(_connection).Options))
{
var fromDoubleTable = context.Entities1
.FromSqlRaw("SELECT Id, Length FROM Entities2")
.First();
Assert.Equal(1234.5, (double)fromDoubleTable.Length);
}
}
}
}

View File

@@ -5,13 +5,19 @@ namespace QWERTYkez.Mensura.Extensions;
internal static partial class CastExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static double ToDouble<T>(this T unit) where T : struct, IMensuraUnit, IEquatable<T>
=> Unsafe.As<T, double>(ref unit);
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static double ToDouble<T>(this T unit)
where T : struct, IMensuraUnit, IEquatable<T> => Unsafe.As<T, double>(ref unit);
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static double Protected<T>(this T? unit)
where T : struct, IMensuraUnit, IEquatable<T> => unit.GetValueOrDefault().ToDouble();
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static T ProtectedU<T>(this T? unit)
where T : struct, IMensuraUnit, IEquatable<T> => unit ?? default;
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static T ToUnit<T>(this double val)
where T : struct, IMensuraUnit, IEquatable<T> => Unsafe.As<double, T>(ref val);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static List<R> WrapAsList<T, R>(this T[] array)
where T : struct, IMensuraUnit, IEquatable<T>

View File

@@ -2,8 +2,8 @@
internal static partial class CollectionsDivideExtensions
{
// === DivideCore === SIMD
internal static void DivideCore<T, R>(this ReadOnlySpan<T> units, double divisor, int len, Span<R> destination)
// === DivCore === SIMD
internal static void DivCore<T, R>(this ReadOnlySpan<T> units, double divisor, int len, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
@@ -40,7 +40,7 @@ internal static partial class CollectionsDivideExtensions
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * invDivisor;
}
}
internal static void DivideCore<T, R>(this ReadOnlySpan<T?> units, double divisor, int len, Span<R?> destination)
internal static void DivCore<T, R>(this ReadOnlySpan<T?> units, double divisor, int len, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
@@ -67,10 +67,10 @@ internal static partial class CollectionsDivideExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (u0.Value.ToDouble() * invDivisor).ToUnit<R>() : null;
d1 = u1.HasValue ? (u1.Value.ToDouble() * invDivisor).ToUnit<R>() : null;
d2 = u2.HasValue ? (u2.Value.ToDouble() * invDivisor).ToUnit<R>() : null;
d3 = u3.HasValue ? (u3.Value.ToDouble() * invDivisor).ToUnit<R>() : null;
d0 = (u0.Protected() * invDivisor).ToUnit<R>();
d1 = (u1.Protected() * invDivisor).ToUnit<R>();
d2 = (u2.Protected() * invDivisor).ToUnit<R>();
d3 = (u3.Protected() * invDivisor).ToUnit<R>();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -78,12 +78,11 @@ internal static partial class CollectionsDivideExtensions
{
T? unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (unit.Value.ToDouble() * invDivisor).ToUnit<R>() : null;
dst = (unit.Protected() * invDivisor).ToUnit<R>();
}
}
//SIMD
internal static void DivideCore<T, R>(this double dividend, ReadOnlySpan<T> units, int len, Span<R> destination)
internal static void DivCore<T, R>(this double dividend, ReadOnlySpan<T> units, int len, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
@@ -118,7 +117,7 @@ internal static partial class CollectionsDivideExtensions
Unsafe.Add(ref dstRef, i) = dividend / Unsafe.Add(ref srcRef, i);
}
}
internal static void DivideCore<T, R>(this double dividend, ReadOnlySpan<T?> units, int len, Span<R?> destination)
internal static void DivCore<T, R>(this double dividend, ReadOnlySpan<T?> units, int len, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
@@ -144,10 +143,10 @@ internal static partial class CollectionsDivideExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (dividend / u0.Value.ToDouble()).ToUnit<R>() : null;
d1 = u1.HasValue ? (dividend / u1.Value.ToDouble()).ToUnit<R>() : null;
d2 = u2.HasValue ? (dividend / u2.Value.ToDouble()).ToUnit<R>() : null;
d3 = u3.HasValue ? (dividend / u3.Value.ToDouble()).ToUnit<R>() : null;
d0 = (dividend / u0.Protected()).ToUnit<R>();
d1 = (dividend / u1.Protected()).ToUnit<R>();
d2 = (dividend / u2.Protected()).ToUnit<R>();
d3 = (dividend / u3.Protected()).ToUnit<R>();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -156,7 +155,7 @@ internal static partial class CollectionsDivideExtensions
T? unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (dividend / unit.Value.ToDouble()).ToUnit<R>() : null;
dst = (dividend / unit.Protected()).ToUnit<R>();
}
}
@@ -174,7 +173,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new R[len];
units.DivideCore(divisor, len, result);
units.DivCore(divisor, len, result);
return result;
}
internal static R?[] Div<T, R>(this T?[] units, double divisor)
@@ -186,7 +185,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new R?[len];
units.DivideCore(divisor, len, result);
units.DivCore(divisor, len, result);
return result;
}
internal static R[] Div<T, R>(this double dividend, T[] units)
@@ -198,7 +197,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new R[len];
dividend.DivideCore(units, len, result);
dividend.DivCore(units, len, result);
return result;
}
internal static R?[] Div<T, R>(this double dividend, T?[] units)
@@ -210,7 +209,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new R?[len];
dividend.DivideCore(units, len, result);
dividend.DivCore(units, len, result);
return result;
}
@@ -223,9 +222,9 @@ internal static partial class CollectionsDivideExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R[count];
DivideCore(CollectionsMarshal.AsSpan(units), divisor, count, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R[count];
DivCore(CollectionsMarshal.AsSpan(units), divisor, count, result);
return result.WrapAsList<R, R>();
}
internal static List<R?> Div<T, R>(this List<T?> units, double divisor)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -235,9 +234,9 @@ internal static partial class CollectionsDivideExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R?[count];
DivideCore(CollectionsMarshal.AsSpan(units), divisor, count, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R?[count];
DivCore(CollectionsMarshal.AsSpan(units), divisor, count, result);
return result.WrapAsList<R, R>();
}
internal static List<R> Div<T, R>(this double dividend, List<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -247,9 +246,9 @@ internal static partial class CollectionsDivideExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R[count];
DivideCore(dividend, CollectionsMarshal.AsSpan(units), count, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R[count];
DivCore(dividend, CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList<R, R>();
}
internal static List<R?> Div<T, R>(this double dividend, List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -259,9 +258,9 @@ internal static partial class CollectionsDivideExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R?[count];
DivideCore(dividend, CollectionsMarshal.AsSpan(units), count, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R?[count];
DivCore(dividend, CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList<R, R>();
}
// === IReadOnlyCollection<T> ===
@@ -275,8 +274,8 @@ internal static partial class CollectionsDivideExtensions
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; }
if (units is T[] array) { array.DivCore(divisor, count, destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).DivCore(divisor, count, destination); return; }
int i = 0;
double invDivisor = 1.0 / divisor;
@@ -293,14 +292,13 @@ internal static partial class CollectionsDivideExtensions
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; }
if (units is T?[] array) { array.DivCore(divisor, count, destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).DivCore(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;
destination[i++] = (item.Protected() * invDivisor).ToUnit<R>();
}
internal static void Div<T, R>(this double dividend, IReadOnlyCollection<T> units, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -312,8 +310,8 @@ internal static partial class CollectionsDivideExtensions
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; }
if (units is T[] array) { dividend.DivCore(array, count, destination); return; }
if (units is List<T> list) { dividend.DivCore(CollectionsMarshal.AsSpan(list), count, destination); return; }
int i = 0;
foreach (var item in units)
@@ -329,13 +327,12 @@ internal static partial class CollectionsDivideExtensions
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; }
if (units is T?[] array) { dividend.DivCore(array, count, destination); return; }
if (units is List<T?> list) { dividend.DivCore(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;
destination[i++] = (dividend / item.Protected()).ToUnit<R>();
}
// === IEnumerable<T> + yeild ===
@@ -353,8 +350,7 @@ internal static partial class CollectionsDivideExtensions
{
double invDivisor = 1.0 / divisor;
foreach (T? item in units)
yield return item.HasValue
? (item.Value.ToDouble() * invDivisor).ToUnit<R>() : null;
yield return (item.Protected() * invDivisor).ToUnit<R>();
}
static IEnumerable<R> DivideIterator<T, R>(double dividend, IEnumerable<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -368,8 +364,7 @@ internal static partial class CollectionsDivideExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (T? item in units)
yield return item.HasValue
? (dividend / item.Value.ToDouble()).ToUnit<R>() : null;
yield return (dividend / item.Protected()).ToUnit<R>();
}
// === IEnumerable<T> ===
@@ -383,7 +378,7 @@ internal static partial class CollectionsDivideExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Div(divisor, arr);
arr.DivCore(divisor, arr.Length, arr);
return arr.ReCast<T, R>();
}
return DivideIterator<T, R>(units, divisor);
@@ -398,7 +393,7 @@ internal static partial class CollectionsDivideExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Div(divisor, arr);
arr.DivCore(divisor, arr.Length, arr);
return arr.ReCast<T, R>();
}
return DivideNullableIterator<T, R>(units, divisor);
@@ -413,7 +408,7 @@ internal static partial class CollectionsDivideExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
dividend.Div(arr, arr);
dividend.DivCore(arr, arr.Length, arr);
return arr.ReCast<T, R>();
}
return DivideIterator<T, R>(dividend, units);
@@ -428,7 +423,7 @@ internal static partial class CollectionsDivideExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
dividend.Div(arr, arr);
dividend.DivCore(arr, arr.Length, arr);
return arr.ReCast<T, R>();
}
return DivideNullableIterator<T, R>(dividend, units);
@@ -447,7 +442,7 @@ internal static partial class CollectionsDivideExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.DivideCore(divisor, len, destination);
units.DivCore(divisor, len, destination);
}
internal static void Div<T>(this ReadOnlySpan<T?> units, double divisor, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -457,7 +452,7 @@ internal static partial class CollectionsDivideExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.DivideCore(divisor, len, destination);
units.DivCore(divisor, len, destination);
}
internal static void Div<T>(this double dividend, ReadOnlySpan<T> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -467,7 +462,7 @@ internal static partial class CollectionsDivideExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
dividend.DivideCore(units, len, destination);
dividend.DivCore(units, len, destination);
}
internal static void Div<T>(this double dividend, ReadOnlySpan<T?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -477,7 +472,7 @@ internal static partial class CollectionsDivideExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
dividend.DivideCore(units, len, destination);
dividend.DivCore(units, len, destination);
}
// === Array ===
@@ -489,7 +484,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new T[len];
Div(units, divisor, result);
units.DivCore(divisor, len, result);
return result;
}
internal static T?[] Div<T>(this T?[] units, double divisor)
@@ -500,7 +495,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new T?[len];
Div(units, divisor, result);
units.DivCore(divisor, len, result);
return result;
}
internal static T[] Div<T>(this double dividend, T[] units)
@@ -511,7 +506,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new T[len];
Div(dividend, units, result);
dividend.DivCore(units, len, result);
return result;
}
internal static T?[] Div<T>(this double dividend, T?[] units)
@@ -522,7 +517,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new T?[len];
Div(dividend, units, result);
dividend.DivCore(units, len, result);
return result;
}
@@ -531,12 +526,12 @@ internal static partial class CollectionsDivideExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[len];
Div(CollectionsMarshal.AsSpan(units), divisor, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T[count];
CollectionsMarshal.AsSpan(units).DivCore(divisor, count, result);
return result.WrapAsList<T, T>();
}
internal static List<T?> Div<T>(this List<T?> units, double divisor)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -545,9 +540,9 @@ internal static partial class CollectionsDivideExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Div(CollectionsMarshal.AsSpan(units), divisor, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T?[count];
CollectionsMarshal.AsSpan(units).DivCore(divisor, count, result);
return result.WrapAsList<T, T>();
}
internal static List<T> Div<T>(this double dividend, List<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -556,9 +551,9 @@ internal static partial class CollectionsDivideExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[count];
Div(dividend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T[count];
dividend.DivCore(CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList<T, T>();
}
internal static List<T?> Div<T>(this double dividend, List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -567,9 +562,9 @@ internal static partial class CollectionsDivideExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Div(dividend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T?[count];
dividend.DivCore(CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList<T, T>();
}
// === IReadOnlyCollection<T> ===
@@ -605,8 +600,7 @@ internal static partial class CollectionsDivideExtensions
int i = 0;
double invDivisor = 1.0 / divisor;
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value.ToDouble() * invDivisor).ToUnit<T>() : null;
destination[i++] = (item.Protected() * invDivisor).ToUnit<T>();
}
internal static void Div<T>(this double dividend, IReadOnlyCollection<T> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -638,8 +632,7 @@ internal static partial class CollectionsDivideExtensions
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? (dividend / item.Value.ToDouble()).ToUnit<T>() : null;
destination[i++] = (dividend / item.Protected()).ToUnit<T>();
}
// === IEnumerable<T> + yeild ===
@@ -655,8 +648,7 @@ internal static partial class CollectionsDivideExtensions
{
double invDivisor = 1.0 / divisor;
foreach (T? item in units)
yield return item.HasValue
? (item.Value.ToDouble() * invDivisor).ToUnit<T>() : null;
yield return (item.Protected() * invDivisor).ToUnit<T>();
}
static IEnumerable<T> DivideIterator<T>(double dividend, IEnumerable<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -668,8 +660,7 @@ internal static partial class CollectionsDivideExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (T? item in units)
yield return item.HasValue
? (dividend / item.Value.ToDouble()).ToUnit<T>() : null;
yield return (dividend / item.Protected()).ToUnit<T>();
}
// === IEnumerable<T> ===
@@ -682,7 +673,7 @@ internal static partial class CollectionsDivideExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Div(divisor, arr);
arr.DivCore(divisor, arr.Length, arr);
return arr;
}
return DivideIterator(units, divisor);
@@ -696,7 +687,7 @@ internal static partial class CollectionsDivideExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Div(divisor, arr);
arr.DivCore(divisor, arr.Length, arr);
return arr;
}
return DivideNullableIterator(units, divisor);
@@ -710,7 +701,7 @@ internal static partial class CollectionsDivideExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
dividend.Div(arr, arr);
dividend.DivCore(arr, arr.Length, arr);
return arr;
}
return DivideIterator(dividend, units);
@@ -724,7 +715,7 @@ internal static partial class CollectionsDivideExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
dividend.Div(arr, arr);
dividend.DivCore(arr, arr.Length, arr);
return arr;
}
return DivideNullableIterator(dividend, units);
@@ -738,7 +729,7 @@ internal static partial class CollectionsDivideExtensions
// === DivideCore === SIMD
// === DivCore === SIMD
internal static void DivCore<R>(this ReadOnlySpan<double> dividends, double unit, int len, Span<R> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
@@ -800,10 +791,10 @@ internal static partial class CollectionsDivideExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (u0.Value * invDivisor).ToUnit<R>() : null;
d1 = u1.HasValue ? (u1.Value * invDivisor).ToUnit<R>() : null;
d2 = u2.HasValue ? (u2.Value * invDivisor).ToUnit<R>() : null;
d3 = u3.HasValue ? (u3.Value * invDivisor).ToUnit<R>() : null;
d0 = ((u0 ?? 0d) * invDivisor).ToUnit<R>();
d1 = ((u1 ?? 0d) * invDivisor).ToUnit<R>();
d2 = ((u2 ?? 0d) * invDivisor).ToUnit<R>();
d3 = ((u3 ?? 0d) * invDivisor).ToUnit<R>();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -811,8 +802,7 @@ internal static partial class CollectionsDivideExtensions
{
var div = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = div.HasValue ? (div.Value * invDivisor).ToUnit<R>() : null;
dst = ((div ?? 0d) * invDivisor).ToUnit<R>();
}
}
//SIMD
@@ -874,10 +864,10 @@ internal static partial class CollectionsDivideExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (unit / u0.Value).ToUnit<R>() : null;
d1 = u1.HasValue ? (unit / u1.Value).ToUnit<R>() : null;
d2 = u2.HasValue ? (unit / u2.Value).ToUnit<R>() : null;
d3 = u3.HasValue ? (unit / u3.Value).ToUnit<R>() : null;
d0 = (unit / (u0 ?? 0d)).ToUnit<R>();
d1 = (unit / (u1 ?? 0d)).ToUnit<R>();
d2 = (unit / (u2 ?? 0d)).ToUnit<R>();
d3 = (unit / (u3 ?? 0d)).ToUnit<R>();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -886,12 +876,12 @@ internal static partial class CollectionsDivideExtensions
var div = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = div.HasValue ? (unit / div.Value).ToUnit<R>() : null;
dst = (unit / (div ?? 0d)).ToUnit<R>();
}
}
// === DivideCore === SIMD
// === DivCore === SIMD
internal static void DivCore(this ReadOnlySpan<double> dividends, double unit, int len, Span<double> dstDouble)
{
// Вместо деления в цикле, умножаем на обратное число (invDivisor)
@@ -949,10 +939,10 @@ internal static partial class CollectionsDivideExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? u0.Value * invDivisor : null;
d1 = u1.HasValue ? u1.Value * invDivisor : null;
d2 = u2.HasValue ? u2.Value * invDivisor : null;
d3 = u3.HasValue ? u3.Value * invDivisor : null;
d0 = (u0 ?? 0d) * invDivisor;
d1 = (u1 ?? 0d) * invDivisor;
d2 = (u2 ?? 0d) * invDivisor;
d3 = (u3 ?? 0d) * invDivisor;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -960,8 +950,7 @@ internal static partial class CollectionsDivideExtensions
{
double? div = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = div.HasValue ? div.Value * invDivisor : null;
dst = (div ?? 0d) * invDivisor;
}
}
//SIMD
@@ -1019,10 +1008,10 @@ internal static partial class CollectionsDivideExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? dUnit / u0.Value : null;
d1 = u1.HasValue ? dUnit / u1.Value : null;
d2 = u2.HasValue ? dUnit / u2.Value : null;
d3 = u3.HasValue ? dUnit / u3.Value : null;
d0 = dUnit / (u0 ?? 0d);
d1 = dUnit / (u1 ?? 0d);
d2 = dUnit / (u2 ?? 0d);
d3 = dUnit / (u3 ?? 0d);
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -1030,8 +1019,7 @@ internal static partial class CollectionsDivideExtensions
{
double? div = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = div.HasValue ? dUnit / div.Value : null;
dst = dUnit / (div ?? 0d);
}
}
@@ -1090,7 +1078,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new T[len];
Div(units, divisor, result);
units.DivCore(divisor.ToDouble(), len, result);
return result;
}
internal static T?[] Div<T>(this double?[] units, T divisor)
@@ -1101,7 +1089,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new T?[len];
Div(units, divisor, result);
units.DivCore(divisor.ToDouble(), len, result);
return result;
}
internal static T[] Div<T>(this T dividend, double[] units)
@@ -1112,7 +1100,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new T[len];
Div(dividend, units, result);
dividend.ToDouble().DivCore(units, len, result);
return result;
}
internal static T?[] Div<T>(this T dividend, double?[] units)
@@ -1123,7 +1111,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new T?[len];
Div(dividend, units, result);
dividend.ToDouble().DivCore(units, len, result);
return result;
}
@@ -1132,12 +1120,12 @@ internal static partial class CollectionsDivideExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[len];
Div(CollectionsMarshal.AsSpan(units), divisor, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T[count];
CollectionsMarshal.AsSpan(units).DivCore(divisor.ToDouble(), count, result);
return result.WrapAsList<T, T>();
}
internal static List<T?> Div<T>(this List<double?> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1146,9 +1134,9 @@ internal static partial class CollectionsDivideExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Div(CollectionsMarshal.AsSpan(units), divisor, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T?[count];
CollectionsMarshal.AsSpan(units).DivCore(divisor.ToDouble(), count, result);
return result.WrapAsList<T, T>();
}
internal static List<T> Div<T>(this T dividend, List<double> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1157,9 +1145,9 @@ internal static partial class CollectionsDivideExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[count];
Div(dividend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T[count];
dividend.ToDouble().DivCore(CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList<T, T>();
}
internal static List<T?> Div<T>(this T dividend, List<double?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1168,9 +1156,9 @@ internal static partial class CollectionsDivideExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Div(dividend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T?[count];
dividend.ToDouble().DivCore(CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList<T, T>();
}
// === IReadOnlyCollection<T> ===
@@ -1206,8 +1194,7 @@ internal static partial class CollectionsDivideExtensions
int i = 0;
double invDivisor = 1.0 / divisor.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value * invDivisor).ToUnit<T>() : null;
destination[i++] = ((item ?? 0d) * invDivisor).ToUnit<T>();
}
internal static void Div<T>(this T dividend, IReadOnlyCollection<double> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1238,9 +1225,9 @@ internal static partial class CollectionsDivideExtensions
if (units is List<double?> list) { dividend.Div(CollectionsMarshal.AsSpan(list), destination); return; }
int i = 0;
var divD = dividend.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue
? (dividend.ToDouble() / item.Value).ToUnit<T>() : null;
destination[i++] = (divD / (item ?? 0d)).ToUnit<T>();
}
// === IEnumerable<T> + yeild ===
@@ -1256,8 +1243,7 @@ internal static partial class CollectionsDivideExtensions
{
double invDivisor = 1.0 / divisor;
foreach (var item in units)
yield return item.HasValue
? (item.Value * invDivisor).ToUnit<T>() : null;
yield return ((item ?? 0d) * invDivisor).ToUnit<T>();
}
static IEnumerable<T> DivideIterator<T>(double dividend, IEnumerable<double> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1269,8 +1255,7 @@ internal static partial class CollectionsDivideExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (var item in units)
yield return item.HasValue
? (dividend / item.Value).ToUnit<T>() : null;
yield return (dividend / (item ?? 0d)).ToUnit<T>();
}
// === IEnumerable<T> ===
@@ -1339,8 +1324,8 @@ internal static partial class CollectionsDivideExtensions
// === DivideCore === SIMD
internal static void DivideCore<T>(this ReadOnlySpan<T> units, double divisor, int len, Span<double> dstDouble)
// === DivCore === SIMD
internal static void DivCore<T>(this ReadOnlySpan<T> units, double divisor, int len, Span<double> dstDouble)
where T : struct, IMensuraUnit, IEquatable<T>
{
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
@@ -1375,7 +1360,7 @@ internal static partial class CollectionsDivideExtensions
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * invDivisor;
}
}
internal static void DivideCore<T>(this ReadOnlySpan<T?> units, double divisor, int len, Span<double?> destination)
internal static void DivCore<T>(this ReadOnlySpan<T?> units, double divisor, int len, Span<double?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
@@ -1401,10 +1386,10 @@ internal static partial class CollectionsDivideExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? u0.Value.ToDouble() * invDivisor : null;
d1 = u1.HasValue ? u1.Value.ToDouble() * invDivisor : null;
d2 = u2.HasValue ? u2.Value.ToDouble() * invDivisor : null;
d3 = u3.HasValue ? u3.Value.ToDouble() * invDivisor : null;
d0 = u0.Protected() * invDivisor;
d1 = u1.Protected() * invDivisor;
d2 = u2.Protected() * invDivisor;
d3 = u3.Protected() * invDivisor;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -1413,11 +1398,11 @@ internal static partial class CollectionsDivideExtensions
T? unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? unit.Value.ToDouble() * invDivisor : null;
dst = unit.Protected() * invDivisor;
}
}
//SIMD
internal static void DivideCore<T>(this double dividend, ReadOnlySpan<T> units, int len, Span<double> dstDouble)
internal static void DivCore<T>(this double dividend, ReadOnlySpan<T> units, int len, Span<double> dstDouble)
where T : struct, IMensuraUnit, IEquatable<T>
{
ReadOnlySpan<double> srcDouble = MemoryMarshal.Cast<T, double>(units);
@@ -1450,7 +1435,7 @@ internal static partial class CollectionsDivideExtensions
Unsafe.Add(ref dstRef, i) = dividend / Unsafe.Add(ref srcRef, i);
}
}
internal static void DivideCore<T>(this double dividend, ReadOnlySpan<T?> units, int len, Span<double?> destination)
internal static void DivCore<T>(this double dividend, ReadOnlySpan<T?> units, int len, Span<double?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
@@ -1475,10 +1460,10 @@ internal static partial class CollectionsDivideExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? dividend / u0.Value.ToDouble() : null;
d1 = u1.HasValue ? dividend / u1.Value.ToDouble() : null;
d2 = u2.HasValue ? dividend / u2.Value.ToDouble() : null;
d3 = u3.HasValue ? dividend / u3.Value.ToDouble() : null;
d0 = dividend / u0.Protected();
d1 = dividend / u1.Protected();
d2 = dividend / u2.Protected();
d3 = dividend / u3.Protected();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -1487,7 +1472,7 @@ internal static partial class CollectionsDivideExtensions
T? unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? dividend / unit.Value.ToDouble() : null;
dst = dividend / unit.Protected();
}
}
@@ -1504,7 +1489,7 @@ internal static partial class CollectionsDivideExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.DivideCore(divisor.ToDouble(), len, destination);
units.DivCore(divisor.ToDouble(), len, destination);
}
internal static void Div<T>(this ReadOnlySpan<T?> units, T divisor, Span<double?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1514,7 +1499,7 @@ internal static partial class CollectionsDivideExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.DivideCore(divisor.ToDouble(), len, destination);
units.DivCore(divisor.ToDouble(), len, destination);
}
internal static void Div<T>(this T dividend, ReadOnlySpan<T> units, Span<double> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1524,7 +1509,7 @@ internal static partial class CollectionsDivideExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
dividend.ToDouble().DivideCore(units, len, destination);
dividend.ToDouble().DivCore(units, len, destination);
}
internal static void Div<T>(this T dividend, ReadOnlySpan<T?> units, Span<double?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1534,7 +1519,7 @@ internal static partial class CollectionsDivideExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
dividend.ToDouble().DivideCore(units, len, destination);
dividend.ToDouble().DivCore(units, len, destination);
}
// === Array ===
@@ -1546,7 +1531,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new T[len];
units.DivideCore(divisor.ToDouble(), len, result);
units.DivCore(divisor.ToDouble(), len, result);
return result.ReCast();
}
internal static double?[] Div<T>(this T?[] units, T divisor)
@@ -1557,7 +1542,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new T?[len];
units.DivideCore(divisor.ToDouble(), len, result);
units.DivCore(divisor.ToDouble(), len, result);
return result.ReCast();
}
internal static double[] Div<T>(this T dividend, T[] units)
@@ -1568,7 +1553,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new T[len];
dividend.ToDouble().DivideCore(units, len, result);
dividend.ToDouble().DivCore(units, len, result);
return result.ReCast();
}
internal static double?[] Div<T>(this T dividend, T?[] units)
@@ -1579,7 +1564,7 @@ internal static partial class CollectionsDivideExtensions
if (len == 0) return [];
var result = new T?[len];
dividend.ToDouble().DivideCore(units, len, result);
dividend.ToDouble().DivCore(units, len, result);
return result.ReCast();
}
@@ -1591,9 +1576,9 @@ internal static partial class CollectionsDivideExtensions
int len = units.Count;
if (len == 0) return [];
var resultArray = new double[len];
CollectionsMarshal.AsSpan(units).DivideCore(divisor.ToDouble(), len, resultArray);
return resultArray.WrapAsList();
var result = new double[len];
CollectionsMarshal.AsSpan(units).DivCore(divisor.ToDouble(), len, result);
return result.WrapAsList();
}
internal static List<double?> Div<T>(this List<T?> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1602,9 +1587,9 @@ internal static partial class CollectionsDivideExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new double?[count];
CollectionsMarshal.AsSpan(units).DivideCore(divisor.ToDouble(), count, resultArray);
return resultArray.WrapAsList();
var result = new double?[count];
CollectionsMarshal.AsSpan(units).DivCore(divisor.ToDouble(), count, result);
return result.WrapAsList();
}
internal static List<double> Div<T>(this T dividend, List<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1613,9 +1598,9 @@ internal static partial class CollectionsDivideExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[count];
dividend.ToDouble().DivideCore(CollectionsMarshal.AsSpan(units), count, resultArray);
return resultArray.WrapAsList();
var result = new T[count];
dividend.ToDouble().DivCore(CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList();
}
internal static List<double?> Div<T>(this T dividend, List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1624,9 +1609,9 @@ internal static partial class CollectionsDivideExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
dividend.ToDouble().DivideCore(CollectionsMarshal.AsSpan(units), count, resultArray);
return resultArray.WrapAsList();
var result = new T?[count];
dividend.ToDouble().DivCore(CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList();
}
// === IReadOnlyCollection<T> ===
@@ -1662,7 +1647,7 @@ internal static partial class CollectionsDivideExtensions
int i = 0;
double invDivisor = 1.0 / divisor.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue ? item.Value.ToDouble() * invDivisor : null;
destination[i++] = item.Protected() * invDivisor;
}
internal static void Div<T>(this T dividend, IReadOnlyCollection<T> units, Span<double> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1696,7 +1681,7 @@ internal static partial class CollectionsDivideExtensions
int i = 0;
var div = dividend.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue ? div / item.Value.ToDouble() : null;
destination[i++] = div / item.Protected();
}
// === IEnumerable<T> + yeild ===
@@ -1712,7 +1697,7 @@ internal static partial class CollectionsDivideExtensions
{
double invDivisor = 1.0 / divisor.ToDouble();
foreach (var item in units)
yield return item.HasValue ? item.Value.ToDouble() * invDivisor : null;
yield return item.Protected() * invDivisor;
}
static IEnumerable<double> DivideIterator<T>(T dividend, IEnumerable<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -1726,7 +1711,7 @@ internal static partial class CollectionsDivideExtensions
{
var div = dividend.ToDouble();
foreach (var item in units)
yield return item.HasValue ? div / item.Value.ToDouble() : null;
yield return div / item.Protected();
}
// === IEnumerable<T> ===
@@ -1739,7 +1724,7 @@ internal static partial class CollectionsDivideExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.DivideCore(divisor.ToDouble(), arr.Length, arr);
arr.DivCore(divisor.ToDouble(), arr.Length, arr);
return arr.ReCast();
}
return DivideIterator(units, divisor);
@@ -1753,7 +1738,7 @@ internal static partial class CollectionsDivideExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.DivideCore(divisor.ToDouble(), arr.Length, arr);
arr.DivCore(divisor.ToDouble(), arr.Length, arr);
return arr.ReCast();
}
return DivideNullableIterator(units, divisor);
@@ -1767,7 +1752,7 @@ internal static partial class CollectionsDivideExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
dividend.ToDouble().DivideCore(arr, arr.Length, arr);
dividend.ToDouble().DivCore(arr, arr.Length, arr);
return arr.ReCast();
}
return DivideIterator(dividend, units);
@@ -1781,7 +1766,7 @@ internal static partial class CollectionsDivideExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
dividend.ToDouble().DivideCore(arr, arr.Length, arr);
dividend.ToDouble().DivCore(arr, arr.Length, arr);
return arr.ReCast();
}
return DivideNullableIterator(dividend, units);

View File

@@ -62,10 +62,10 @@ internal static partial class CollectionsMinusExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (u0.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
d1 = u1.HasValue ? (u1.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
d2 = u2.HasValue ? (u2.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
d3 = u3.HasValue ? (u3.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
d0 = (u0.Protected() - subtrahend).ToUnit<R>();
d1 = (u1.Protected() - subtrahend).ToUnit<R>();
d2 = (u2.Protected() - subtrahend).ToUnit<R>();
d3 = (u3.Protected() - subtrahend).ToUnit<R>();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -73,8 +73,7 @@ internal static partial class CollectionsMinusExtensions
{
T? unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (unit.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
dst = (unit.Protected() - subtrahend).ToUnit<R>();
}
}
//SIMD
@@ -139,10 +138,10 @@ internal static partial class CollectionsMinusExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (minuend - u0.Value.ToDouble()).ToUnit<R>() : null;
d1 = u1.HasValue ? (minuend - u1.Value.ToDouble()).ToUnit<R>() : null;
d2 = u2.HasValue ? (minuend - u2.Value.ToDouble()).ToUnit<R>() : null;
d3 = u3.HasValue ? (minuend - u3.Value.ToDouble()).ToUnit<R>() : null;
d0 = (minuend - u0.Protected()).ToUnit<R>();
d1 = (minuend - u1.Protected()).ToUnit<R>();
d2 = (minuend - u2.Protected()).ToUnit<R>();
d3 = (minuend - u3.Protected()).ToUnit<R>();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -150,8 +149,7 @@ internal static partial class CollectionsMinusExtensions
{
T? unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (minuend - unit.Value.ToDouble()).ToUnit<R>() : null;
dst = (minuend - unit.Protected()).ToUnit<R>();
}
}
@@ -218,9 +216,9 @@ internal static partial class CollectionsMinusExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R[count];
MinusCore(CollectionsMarshal.AsSpan(units), subtrahend, count, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R[count];
MinusCore(CollectionsMarshal.AsSpan(units), subtrahend, count, result);
return result.WrapAsList<R, R>();
}
internal static List<R?> Minus<T, R>(this List<T?> units, double subtrahend)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -230,9 +228,9 @@ internal static partial class CollectionsMinusExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R?[count];
MinusCore(CollectionsMarshal.AsSpan(units), subtrahend, count, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R?[count];
MinusCore(CollectionsMarshal.AsSpan(units), subtrahend, count, result);
return result.WrapAsList<R, R>();
}
internal static List<R> Minus<T, R>(this double minuend, List<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -242,9 +240,9 @@ internal static partial class CollectionsMinusExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R[count];
MinusCore(minuend, CollectionsMarshal.AsSpan(units), count, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R[count];
MinusCore(minuend, CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList<R, R>();
}
internal static List<R?> Minus<T, R>(this double minuend, List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -254,9 +252,9 @@ internal static partial class CollectionsMinusExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R?[count];
MinusCore(minuend, CollectionsMarshal.AsSpan(units), count, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R?[count];
MinusCore(minuend, CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList<R, R>();
}
// === IReadOnlyCollection<T> ===
@@ -292,8 +290,7 @@ internal static partial class CollectionsMinusExtensions
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
destination[i++] = (item.Protected() - subtrahend).ToUnit<R>();
}
internal static void Minus<T, R>(this double minuend, IReadOnlyCollection<T> units, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -327,8 +324,7 @@ internal static partial class CollectionsMinusExtensions
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? (minuend - item.Value.ToDouble()).ToUnit<R>() : null;
destination[i++] = (minuend - item.Protected()).ToUnit<R>();
}
// === IEnumerable<T> + yeild ===
@@ -344,8 +340,7 @@ internal static partial class CollectionsMinusExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (T? item in units)
yield return item.HasValue
? (item.Value.ToDouble() - subtrahend).ToUnit<R>() : null;
yield return (item.Protected() - subtrahend).ToUnit<R>();
}
static IEnumerable<R> MinusIterator<T, R>(double minuend, IEnumerable<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -359,8 +354,7 @@ internal static partial class CollectionsMinusExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (T? item in units)
yield return item.HasValue
? (minuend - item.Value.ToDouble()).ToUnit<R>() : null;
yield return (minuend - item.Protected()).ToUnit<R>();
}
// === IEnumerable<T> ===
@@ -374,7 +368,7 @@ internal static partial class CollectionsMinusExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Minus(subtrahend, arr);
arr.MinusCore(subtrahend, arr.Length, arr);
return arr.ReCast<T, R>();
}
return MinusIterator<T, R>(units, subtrahend);
@@ -389,7 +383,7 @@ internal static partial class CollectionsMinusExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Minus(subtrahend, arr);
arr.MinusCore(subtrahend, arr.Length, arr);
return arr.ReCast<T, R>();
}
return MinusNullableIterator<T, R>(units, subtrahend);
@@ -404,7 +398,7 @@ internal static partial class CollectionsMinusExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
minuend.Minus(arr, arr);
minuend.MinusCore(arr, arr.Length, arr);
return arr.ReCast<T, R>();
}
return MinusIterator<T, R>(minuend, units);
@@ -419,7 +413,7 @@ internal static partial class CollectionsMinusExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
minuend.Minus(arr, arr);
minuend.MinusCore(arr, arr.Length, arr);
return arr.ReCast<T, R>();
}
return MinusNullableIterator<T, R>(minuend, units);
@@ -481,7 +475,7 @@ internal static partial class CollectionsMinusExtensions
if (len == 0) return [];
var result = new T[len];
Minus(units, subtrahend, result);
units.MinusCore(subtrahend, len, result);
return result;
}
internal static T?[] Minus<T>(this T?[] units, double subtrahend)
@@ -492,7 +486,7 @@ internal static partial class CollectionsMinusExtensions
if (len == 0) return [];
var result = new T?[len];
Minus(units, subtrahend, result);
units.MinusCore(subtrahend, len, result);
return result;
}
internal static T[] Minus<T>(this double minuend, T[] units)
@@ -503,7 +497,7 @@ internal static partial class CollectionsMinusExtensions
if (len == 0) return [];
var result = new T[len];
Minus(minuend, units, result);
minuend.MinusCore(units, len, result);
return result;
}
internal static T?[] Minus<T>(this double minuend, T?[] units)
@@ -514,7 +508,7 @@ internal static partial class CollectionsMinusExtensions
if (len == 0) return [];
var result = new T?[len];
Minus(minuend, units, result);
minuend.MinusCore(units, len, result);
return result;
}
@@ -523,12 +517,12 @@ internal static partial class CollectionsMinusExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[len];
Minus(CollectionsMarshal.AsSpan(units), subtrahend, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T[count];
CollectionsMarshal.AsSpan(units).MinusCore(subtrahend, count, result);
return result.WrapAsList<T, T>();
}
internal static List<T?> Minus<T>(this List<T?> units, double subtrahend)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -537,9 +531,9 @@ internal static partial class CollectionsMinusExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Minus(CollectionsMarshal.AsSpan(units), subtrahend, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T?[count];
CollectionsMarshal.AsSpan(units).MinusCore(subtrahend, count, result);
return result.WrapAsList<T, T>();
}
internal static List<T> Minus<T>(this double minuend, List<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -548,9 +542,9 @@ internal static partial class CollectionsMinusExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[count];
Minus(minuend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T[count];
minuend.MinusCore(CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList<T, T>();
}
internal static List<T?> Minus<T>(this double minuend, List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -559,9 +553,9 @@ internal static partial class CollectionsMinusExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Minus(minuend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T?[count];
minuend.MinusCore(CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList<T, T>();
}
// === IReadOnlyCollection<T> ===
@@ -574,8 +568,8 @@ internal static partial class CollectionsMinusExtensions
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; }
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)
@@ -590,13 +584,12 @@ internal static partial class CollectionsMinusExtensions
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; }
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<T>() : null;
destination[i++] = (item.Protected() - subtrahend).ToUnit<T>();
}
internal static void Minus<T>(this double minuend, IReadOnlyCollection<T> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -607,8 +600,8 @@ internal static partial class CollectionsMinusExtensions
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; }
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)
@@ -623,13 +616,12 @@ internal static partial class CollectionsMinusExtensions
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; }
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<T>() : null;
destination[i++] = (minuend - item.Protected()).ToUnit<T>();
}
// === IEnumerable<T> + yeild ===
@@ -643,8 +635,7 @@ internal static partial class CollectionsMinusExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (T? item in units)
yield return item.HasValue
? (item.Value.ToDouble() - subtrahend).ToUnit<T>() : null;
yield return (item.Protected() - subtrahend).ToUnit<T>();
}
static IEnumerable<T> MinusIterator<T>(double minuend, IEnumerable<T> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -656,8 +647,7 @@ internal static partial class CollectionsMinusExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (T? item in units)
yield return item.HasValue
? (minuend - item.Value.ToDouble()).ToUnit<T>() : null;
yield return (minuend - item.Protected()).ToUnit<T>();
}
// === IEnumerable<T> ===
@@ -670,7 +660,7 @@ internal static partial class CollectionsMinusExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Minus(subtrahend, arr);
arr.MinusCore(subtrahend, arr.Length, arr);
return arr;
}
return MinusIterator(units, subtrahend);
@@ -684,7 +674,7 @@ internal static partial class CollectionsMinusExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Minus(subtrahend, arr);
arr.MinusCore(subtrahend, arr.Length, arr);
return arr;
}
return MinusNullableIterator(units, subtrahend);
@@ -698,7 +688,7 @@ internal static partial class CollectionsMinusExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
minuend.Minus(arr, arr);
minuend.MinusCore(arr, arr.Length, arr);
return arr;
}
return MinusIterator(minuend, units);
@@ -712,7 +702,7 @@ internal static partial class CollectionsMinusExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
minuend.Minus(arr, arr);
minuend.MinusCore(arr, arr.Length, arr);
return arr;
}
return MinusNullableIterator(minuend, units);
@@ -783,10 +773,10 @@ internal static partial class CollectionsMinusExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (u0.Value - subtrahend).ToUnit<R>() : null;
d1 = u1.HasValue ? (u1.Value - subtrahend).ToUnit<R>() : null;
d2 = u2.HasValue ? (u2.Value - subtrahend).ToUnit<R>() : null;
d3 = u3.HasValue ? (u3.Value - subtrahend).ToUnit<R>() : null;
d0 = ((u0 ?? 0d) - subtrahend).ToUnit<R>();
d1 = ((u1 ?? 0d) - subtrahend).ToUnit<R>();
d2 = ((u2 ?? 0d) - subtrahend).ToUnit<R>();
d3 = ((u3 ?? 0d) - subtrahend).ToUnit<R>();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -794,8 +784,7 @@ internal static partial class CollectionsMinusExtensions
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (unit.Value - subtrahend).ToUnit<R>() : null;
dst = ((unit ?? 0d) - subtrahend).ToUnit<R>();
}
}
//SIMD
@@ -857,10 +846,10 @@ internal static partial class CollectionsMinusExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (minuend - u0.Value).ToUnit<R>() : null;
d1 = u1.HasValue ? (minuend - u1.Value).ToUnit<R>() : null;
d2 = u2.HasValue ? (minuend - u2.Value).ToUnit<R>() : null;
d3 = u3.HasValue ? (minuend - u3.Value).ToUnit<R>() : null;
d0 = (minuend - (u0 ?? 0d)).ToUnit<R>();
d1 = (minuend - (u1 ?? 0d)).ToUnit<R>();
d2 = (minuend - (u2 ?? 0d)).ToUnit<R>();
d3 = (minuend - (u3 ?? 0d)).ToUnit<R>();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -868,13 +857,12 @@ internal static partial class CollectionsMinusExtensions
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (minuend - unit.Value).ToUnit<R>() : null;
dst = (minuend - (unit ?? 0d)).ToUnit<R>();
}
}
// === DivideCore === SIMD
// === DivCore === SIMD
internal static void MinusCore(this ReadOnlySpan<double> srcDouble, double subtrahend, int len, Span<double> dstDouble)
{
var vectorizedSubtrahend = new Vector<double>(subtrahend);
@@ -927,10 +915,10 @@ internal static partial class CollectionsMinusExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? u0.Value - subtrahend : null;
d1 = u1.HasValue ? u1.Value - subtrahend : null;
d2 = u2.HasValue ? u2.Value - subtrahend : null;
d3 = u3.HasValue ? u3.Value - subtrahend : null;
d0 = (u0 ?? 0d) - subtrahend;
d1 = (u1 ?? 0d) - subtrahend;
d2 = (u2 ?? 0d) - subtrahend;
d3 = (u3 ?? 0d) - subtrahend;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -938,8 +926,7 @@ internal static partial class CollectionsMinusExtensions
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? unit.Value - subtrahend : null;
dst = (unit ?? 0d) - subtrahend;
}
}
//SIMD
@@ -997,10 +984,10 @@ internal static partial class CollectionsMinusExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? minuend - u0.Value : null;
d1 = u1.HasValue ? minuend - u1.Value : null;
d2 = u2.HasValue ? minuend - u2.Value : null;
d3 = u3.HasValue ? minuend - u3.Value : null;
d0 = minuend - u0 ?? 0d;
d1 = minuend - u1 ?? 0d;
d2 = minuend - u2 ?? 0d;
d3 = minuend - u3 ?? 0d;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -1008,8 +995,7 @@ internal static partial class CollectionsMinusExtensions
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? minuend - unit.Value : null;
dst = minuend - unit ?? 0d;
}
}
@@ -1018,7 +1004,7 @@ internal static partial class CollectionsMinusExtensions
// === ReadOnlySpan
internal static void Minus<T>(this ReadOnlySpan<double> units, T divisor, Span<T> destination)
internal static void Minus<T>(this ReadOnlySpan<double> units, T subtrahend, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
@@ -1026,9 +1012,9 @@ internal static partial class CollectionsMinusExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.MinusCore(divisor.ToDouble(), len, destination);
units.MinusCore(subtrahend.ToDouble(), len, destination);
}
internal static void Minus<T>(this ReadOnlySpan<double?> units, T divisor, Span<T?> destination)
internal static void Minus<T>(this ReadOnlySpan<double?> units, T subtrahend, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
@@ -1036,9 +1022,9 @@ internal static partial class CollectionsMinusExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.MinusCore(divisor.ToDouble(), len, destination);
units.MinusCore(subtrahend.ToDouble(), len, destination);
}
internal static void Minus<T>(this T dividend, ReadOnlySpan<double> units, Span<T> destination)
internal static void Minus<T>(this T minuend, ReadOnlySpan<double> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
@@ -1046,9 +1032,9 @@ internal static partial class CollectionsMinusExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
dividend.ToDouble().MinusCore(units, len, destination);
minuend.ToDouble().MinusCore(units, len, destination);
}
internal static void Minus<T>(this T dividend, ReadOnlySpan<double?> units, Span<T?> destination)
internal static void Minus<T>(this T minuend, ReadOnlySpan<double?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units.IsEmpty) return;
@@ -1056,11 +1042,11 @@ internal static partial class CollectionsMinusExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
dividend.ToDouble().MinusCore(units, len, destination);
minuend.ToDouble().MinusCore(units, len, destination);
}
// === Array ===
internal static T[] Minus<T>(this double[] units, T divisor)
internal static T[] Minus<T>(this double[] units, T subtrahend)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
@@ -1068,10 +1054,10 @@ internal static partial class CollectionsMinusExtensions
if (len == 0) return [];
var result = new T[len];
Minus(units, divisor, result);
units.MinusCore(subtrahend.ToDouble(), len, result);
return result;
}
internal static T?[] Minus<T>(this double?[] units, T divisor)
internal static T?[] Minus<T>(this double?[] units, T subtrahend)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
@@ -1079,10 +1065,10 @@ internal static partial class CollectionsMinusExtensions
if (len == 0) return [];
var result = new T?[len];
Minus(units, divisor, result);
units.MinusCore(subtrahend.ToDouble(), len, result);
return result;
}
internal static T[] Minus<T>(this T dividend, double[] units)
internal static T[] Minus<T>(this T minuend, double[] units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
@@ -1090,10 +1076,10 @@ internal static partial class CollectionsMinusExtensions
if (len == 0) return [];
var result = new T[len];
Minus(dividend, units, result);
minuend.ToDouble().MinusCore(units, len, result);
return result;
}
internal static T?[] Minus<T>(this T dividend, double?[] units)
internal static T?[] Minus<T>(this T minuend, double?[] units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
@@ -1101,58 +1087,58 @@ internal static partial class CollectionsMinusExtensions
if (len == 0) return [];
var result = new T?[len];
Minus(dividend, units, result);
minuend.ToDouble().MinusCore(units, len, result);
return result;
}
// === List<T> ===
internal static List<T> Minus<T>(this List<double> units, T divisor)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
var resultArray = new T[len];
Minus(CollectionsMarshal.AsSpan(units), divisor, resultArray);
return resultArray.WrapAsList<T, T>();
}
internal static List<T?> Minus<T>(this List<double?> units, T divisor)
internal static List<T> Minus<T>(this List<double> units, T subtrahend)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Minus(CollectionsMarshal.AsSpan(units), divisor, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T[count];
CollectionsMarshal.AsSpan(units).MinusCore(subtrahend.ToDouble(), count, result);
return result.WrapAsList<T, T>();
}
internal static List<T> Minus<T>(this T dividend, List<double> units)
internal static List<T?> Minus<T>(this List<double?> units, T subtrahend)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[count];
Minus(dividend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T?[count];
CollectionsMarshal.AsSpan(units).MinusCore(subtrahend.ToDouble(), count, result);
return result.WrapAsList<T, T>();
}
internal static List<T?> Minus<T>(this T dividend, List<double?> units)
internal static List<T> Minus<T>(this T minuend, List<double> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Minus(dividend, CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T[count];
minuend.ToDouble().MinusCore(CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList<T, T>();
}
internal static List<T?> Minus<T>(this T minuend, List<double?> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int count = units.Count;
if (count == 0) return [];
var result = new T?[count];
minuend.ToDouble().MinusCore(CollectionsMarshal.AsSpan(units), count, result);
return result.WrapAsList<T, 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 subtrahend, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
@@ -1161,15 +1147,15 @@ internal static partial class CollectionsMinusExtensions
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; }
if (units is double[] array) { array.MinusCore(subtrahend.ToDouble(), count, destination); return; }
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).MinusCore(subtrahend.ToDouble(), count, destination); return; }
int i = 0;
double invMinusisor = 1.0 / divisor.ToDouble();
double invMinusisor = 1.0 / subtrahend.ToDouble();
foreach (var item in units)
destination[i++] = (item * invMinusisor).ToUnit<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 subtrahend, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
@@ -1178,16 +1164,15 @@ internal static partial class CollectionsMinusExtensions
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; }
if (units is double?[] array) { array.MinusCore(subtrahend.ToDouble(), count, destination); return; }
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).MinusCore(subtrahend.ToDouble(), count, destination); return; }
int i = 0;
double invMinusisor = 1.0 / divisor.ToDouble();
double invMinusisor = 1.0 / subtrahend.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value * invMinusisor).ToUnit<T>() : null;
destination[i++] = ((item ?? 0d) * invMinusisor).ToUnit<T>();
}
internal static void Minus<T>(this T dividend, IReadOnlyCollection<double> units, Span<T> destination)
internal static void Minus<T>(this T minuend, IReadOnlyCollection<double> units, Span<T> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
@@ -1196,14 +1181,15 @@ internal static partial class CollectionsMinusExtensions
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; }
if (units is double[] array) { minuend.ToDouble().MinusCore(array, count, destination); return; }
if (units is List<double> list) { minuend.ToDouble().MinusCore(CollectionsMarshal.AsSpan(list), count, destination); return; }
int i = 0;
var div = minuend.ToDouble();
foreach (var item in units)
destination[i++] = (dividend.ToDouble() / item).ToUnit<T>();
destination[i++] = (div / item).ToUnit<T>();
}
internal static void Minus<T>(this T dividend, IReadOnlyCollection<double?> units, Span<T?> destination)
internal static void Minus<T>(this T minuend, IReadOnlyCollection<double?> units, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return;
@@ -1212,100 +1198,98 @@ internal static partial class CollectionsMinusExtensions
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; }
if (units is double?[] array) { minuend.ToDouble().MinusCore(array, count, destination); return; }
if (units is List<double?> list) { minuend.ToDouble().MinusCore(CollectionsMarshal.AsSpan(list), count, destination); return; }
int i = 0;
var div = minuend.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue
? (dividend.ToDouble() / item.Value).ToUnit<T>() : null;
destination[i++] = (div / (item ?? 0d)).ToUnit<T>();
}
// === IEnumerable<T> + yeild ===
static IEnumerable<T> MinusideIterator<T>(IEnumerable<double> units, double divisor)
static IEnumerable<T> MinusideIterator<T>(IEnumerable<double> units, double subtrahend)
where T : struct, IMensuraUnit, IEquatable<T>
{
double invMinusisor = 1.0 / divisor;
double invMinusisor = 1.0 / subtrahend;
foreach (var item in units)
yield return (item * invMinusisor).ToUnit<T>();
}
static IEnumerable<T?> MinusideNullableIterator<T>(IEnumerable<double?> units, double divisor)
static IEnumerable<T?> MinusideNullableIterator<T>(IEnumerable<double?> units, double subtrahend)
where T : struct, IMensuraUnit, IEquatable<T>
{
double invMinusisor = 1.0 / divisor;
double invMinusisor = 1.0 / subtrahend;
foreach (var item in units)
yield return item.HasValue
? (item.Value * invMinusisor).ToUnit<T>() : null;
yield return ((item ?? 0d) * invMinusisor).ToUnit<T>();
}
static IEnumerable<T> MinusideIterator<T>(double dividend, IEnumerable<double> units)
static IEnumerable<T> MinusideIterator<T>(double minuend, IEnumerable<double> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (var item in units)
yield return (dividend / item).ToUnit<T>();
yield return (minuend / item).ToUnit<T>();
}
static IEnumerable<T?> MinusideNullableIterator<T>(double dividend, IEnumerable<double?> units)
static IEnumerable<T?> MinusideNullableIterator<T>(double minuend, IEnumerable<double?> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (var item in units)
yield return item.HasValue
? (dividend / item.Value).ToUnit<T>() : null;
yield return (minuend / (item ?? 0d)).ToUnit<T>();
}
// === IEnumerable<T> ===
internal static IEnumerable<T> Minus<T>(this IEnumerable<double> units, T divisor)
internal static IEnumerable<T> Minus<T>(this IEnumerable<double> units, T subtrahend)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is double[] array) return array.Minus(divisor);
if (units is List<double> list) return list.Minus(divisor);
if (units is double[] array) return array.Minus(subtrahend);
if (units is List<double> list) return list.Minus(subtrahend);
if (units is IReadOnlyCollection<double> roc)
{
var arr = roc.ToArray();
arr.MinusCore(divisor.ToDouble(), arr.Length, arr);
arr.MinusCore(subtrahend.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
return MinusideIterator<T>(units, divisor.ToDouble());
return MinusideIterator<T>(units, subtrahend.ToDouble());
}
internal static IEnumerable<T?> Minus<T>(this IEnumerable<double?> units, T divisor)
internal static IEnumerable<T?> Minus<T>(this IEnumerable<double?> units, T subtrahend)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is double?[] array) return array.Minus(divisor);
if (units is List<double?> list) return list.Minus(divisor);
if (units is double?[] array) return array.Minus(subtrahend);
if (units is List<double?> list) return list.Minus(subtrahend);
if (units is IReadOnlyCollection<double?> roc)
{
var arr = roc.ToArray();
arr.MinusCore(divisor.ToDouble(), arr.Length, arr);
arr.MinusCore(subtrahend.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
return MinusideNullableIterator<T>(units, divisor.ToDouble());
return MinusideNullableIterator<T>(units, subtrahend.ToDouble());
}
internal static IEnumerable<T> Minus<T>(this T dividend, IEnumerable<double> units)
internal static IEnumerable<T> Minus<T>(this T minuend, IEnumerable<double> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is double[] array) return dividend.Minus(array);
if (units is List<double> list) return dividend.Minus(list);
if (units is double[] array) return minuend.Minus(array);
if (units is List<double> list) return minuend.Minus(list);
if (units is IReadOnlyCollection<double> roc)
{
var arr = roc.ToArray();
dividend.ToDouble().MinusCore(arr, arr.Length, arr);
minuend.ToDouble().MinusCore(arr, arr.Length, arr);
return arr.ReCast<T>();
}
return MinusideIterator<T>(dividend.ToDouble(), units);
return MinusideIterator<T>(minuend.ToDouble(), units);
}
internal static IEnumerable<T?> Minus<T>(this T dividend, IEnumerable<double?> units)
internal static IEnumerable<T?> Minus<T>(this T minuend, IEnumerable<double?> units)
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
if (units is double?[] array) return dividend.Minus(array);
if (units is List<double?> list) return dividend.Minus(list);
if (units is double?[] array) return minuend.Minus(array);
if (units is List<double?> list) return minuend.Minus(list);
if (units is IReadOnlyCollection<double?> roc)
{
var arr = roc.ToArray();
dividend.ToDouble().MinusCore(arr, arr.Length, arr);
minuend.ToDouble().MinusCore(arr, arr.Length, arr);
return arr.ReCast<T>();
}
return MinusideNullableIterator<T>(dividend.ToDouble(), units);
return MinusideNullableIterator<T>(minuend.ToDouble(), units);
}
}

View File

@@ -2,8 +2,8 @@
internal static partial class CollectionsMultiplyExtensions
{
// === MultiplyCore === SIMD
internal static void MultiplyCore<T, R>(this ReadOnlySpan<T> units, double multiplicator, int len, Span<R> destination)
// === MulCore === SIMD
internal static void MulCore<T, R>(this ReadOnlySpan<T> units, double multiplicator, int len, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
@@ -35,7 +35,7 @@ internal static partial class CollectionsMultiplyExtensions
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * multiplicator;
}
}
internal static void MultiplyCore<T, R>(this ReadOnlySpan<T?> units, double multiplicator, int len, Span<R?> destination)
internal static void MulCore<T, R>(this ReadOnlySpan<T?> units, double multiplicator, int len, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
@@ -61,10 +61,10 @@ internal static partial class CollectionsMultiplyExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (u0.Value.ToDouble() * multiplicator).ToUnit<R>() : null;
d1 = u1.HasValue ? (u1.Value.ToDouble() * multiplicator).ToUnit<R>() : null;
d2 = u2.HasValue ? (u2.Value.ToDouble() * multiplicator).ToUnit<R>() : null;
d3 = u3.HasValue ? (u3.Value.ToDouble() * multiplicator).ToUnit<R>() : null;
d0 = (u0.Protected() * multiplicator).ToUnit<R>();
d1 = (u1.Protected() * multiplicator).ToUnit<R>();
d2 = (u2.Protected() * multiplicator).ToUnit<R>();
d3 = (u3.Protected() * multiplicator).ToUnit<R>();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -72,20 +72,19 @@ internal static partial class CollectionsMultiplyExtensions
{
T? unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (unit.Value.ToDouble() * multiplicator).ToUnit<R>() : null;
dst = (unit.Protected() * multiplicator).ToUnit<R>();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void MultiplyCore<T, R>(this double multiplicator, ReadOnlySpan<T> units, int len, Span<R> destination)
internal static void MulCore<T, R>(this double multiplicator, ReadOnlySpan<T> units, int len, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R> => units.MultiplyCore(multiplicator, len, destination);
where R : struct, IMensuraUnit, IEquatable<R> => units.MulCore(multiplicator, len, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void MultiplyCore<T, R>(this double multiplicator, ReadOnlySpan<T?> units, int len, Span<R?> destination)
internal static void MulCore<T, R>(this double multiplicator, ReadOnlySpan<T?> units, int len, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R> => units.MultiplyCore(multiplicator, len, destination);
where R : struct, IMensuraUnit, IEquatable<R> => units.MulCore(multiplicator, len, destination);
@@ -100,7 +99,7 @@ internal static partial class CollectionsMultiplyExtensions
if (len == 0) return [];
var result = new R[len];
units.MultiplyCore(multiplicator, len, result);
units.MulCore(multiplicator, len, result);
return result;
}
internal static R?[] Mul<T, R>(this T?[] units, double multiplicator)
@@ -112,7 +111,7 @@ internal static partial class CollectionsMultiplyExtensions
if (len == 0) return [];
var result = new R?[len];
units.MultiplyCore(multiplicator, len, result);
units.MulCore(multiplicator, len, result);
return result;
}
@@ -135,9 +134,9 @@ internal static partial class CollectionsMultiplyExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R[count];
MultiplyCore(CollectionsMarshal.AsSpan(units), multiplicator, count, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R[count];
MulCore(CollectionsMarshal.AsSpan(units), multiplicator, count, result);
return result.WrapAsList<R, R>();
}
internal static List<R?> Mul<T, R>(this List<T?> units, double multiplicator)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -147,9 +146,9 @@ internal static partial class CollectionsMultiplyExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R?[count];
MultiplyCore(CollectionsMarshal.AsSpan(units), multiplicator, count, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R?[count];
MulCore(CollectionsMarshal.AsSpan(units), multiplicator, count, result);
return result.WrapAsList<R, R>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -173,8 +172,8 @@ internal static partial class CollectionsMultiplyExtensions
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; }
if (units is T[] array) { MulCore(array, multiplicator, count, destination); return; }
if (units is List<T> list) { MulCore(CollectionsMarshal.AsSpan(list), multiplicator, count, destination); return; }
int i = 0;
foreach (var item in units)
@@ -190,13 +189,12 @@ internal static partial class CollectionsMultiplyExtensions
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; }
if (units is T?[] array) { MulCore(array, multiplicator, count, destination); return; }
if (units is List<T?> list) { MulCore(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;
destination[i++] = (item.Protected() * multiplicator).ToUnit<R>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -222,8 +220,7 @@ internal static partial class CollectionsMultiplyExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (T? item in units)
yield return item.HasValue
? (item.Value.ToDouble() * multiplicator).ToUnit<R>() : null;
yield return (item.Protected() * multiplicator).ToUnit<R>();
}
// === IEnumerable<T> ===
@@ -237,7 +234,7 @@ internal static partial class CollectionsMultiplyExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Mul(multiplicator, arr);
arr.MulCore(multiplicator, arr.Length, arr);
return arr.ReCast<T, R>();
}
return MultiplyIterator<T, R>(units, multiplicator);
@@ -252,7 +249,7 @@ internal static partial class CollectionsMultiplyExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Mul(multiplicator, arr);
arr.MulCore(multiplicator, arr.Length, arr);
return arr.ReCast<T, R>();
}
return MultiplyNullableIterator<T, R>(units, multiplicator);
@@ -280,7 +277,7 @@ internal static partial class CollectionsMultiplyExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.MultiplyCore(multiplicator, len, destination);
units.MulCore(multiplicator, len, destination);
}
internal static void Mul<T>(this ReadOnlySpan<T?> units, double multiplicator, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -290,7 +287,7 @@ internal static partial class CollectionsMultiplyExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.MultiplyCore(multiplicator, len, destination);
units.MulCore(multiplicator, len, destination);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -310,7 +307,7 @@ internal static partial class CollectionsMultiplyExtensions
if (len == 0) return [];
var result = new T[len];
Mul(units, multiplicator, result);
units.MulCore(multiplicator, len, result);
return result;
}
internal static T?[] Mul<T>(this T?[] units, double multiplicator)
@@ -321,7 +318,7 @@ internal static partial class CollectionsMultiplyExtensions
if (len == 0) return [];
var result = new T?[len];
Mul(units, multiplicator, result);
units.MulCore(multiplicator, len, result);
return result;
}
@@ -338,12 +335,12 @@ internal static partial class CollectionsMultiplyExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[len];
Mul(CollectionsMarshal.AsSpan(units), multiplicator, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T[count];
CollectionsMarshal.AsSpan(units).MulCore(multiplicator, count, result);
return result.WrapAsList<T, T>();
}
internal static List<T?> Mul<T>(this List<T?> units, double multiplicator)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -352,9 +349,9 @@ internal static partial class CollectionsMultiplyExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Mul(CollectionsMarshal.AsSpan(units), multiplicator, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T?[count];
CollectionsMarshal.AsSpan(units).MulCore(multiplicator, count, result);
return result.WrapAsList<T, T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -375,8 +372,8 @@ internal static partial class CollectionsMultiplyExtensions
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; }
if (units is T[] array) { array.MulCore(multiplicator, array.Length, destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).MulCore(multiplicator, list.Count, destination); return; }
int i = 0;
foreach (var item in units)
@@ -391,13 +388,12 @@ internal static partial class CollectionsMultiplyExtensions
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; }
if (units is T?[] array) { array.MulCore(multiplicator, array.Length, destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).MulCore(multiplicator, list.Count, destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value.ToDouble() * multiplicator).ToUnit<T>() : null;
destination[i++] = (item.Protected() * multiplicator).ToUnit<T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -419,8 +415,7 @@ internal static partial class CollectionsMultiplyExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (T? item in units)
yield return item.HasValue
? (item.Value.ToDouble() * multiplicator).ToUnit<T>() : null;
yield return (item.Protected() * multiplicator).ToUnit<T>();
}
// === IEnumerable<T> ===
@@ -433,7 +428,7 @@ internal static partial class CollectionsMultiplyExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Mul(multiplicator, arr);
arr.MulCore(multiplicator, arr.Length, arr);
return arr;
}
return MultiplyIterator(units, multiplicator);
@@ -447,7 +442,7 @@ internal static partial class CollectionsMultiplyExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Mul(multiplicator, arr);
arr.MulCore(multiplicator, arr.Length, arr);
return arr;
}
return MultiplyNullableIterator(units, multiplicator);
@@ -469,8 +464,8 @@ internal static partial class CollectionsMultiplyExtensions
// === MultiplyCore === SIMD
internal static void MultiplyCore<R>(this ReadOnlySpan<double> srcDouble, double multiplicator, int len, Span<R> destination)
// === MulCore === SIMD
internal static void MulCore<R>(this ReadOnlySpan<double> srcDouble, double multiplicator, int len, Span<R> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
Span<double> dstDouble = MemoryMarshal.Cast<R, double>(destination);
@@ -500,7 +495,7 @@ internal static partial class CollectionsMultiplyExtensions
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * multiplicator;
}
}
internal static void MultiplyCore<R>(this ReadOnlySpan<double?> units, double multiplicator, int len, Span<R?> destination)
internal static void MulCore<R>(this ReadOnlySpan<double?> units, double multiplicator, int len, Span<R?> destination)
where R : struct, IMensuraUnit, IEquatable<R>
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
@@ -525,10 +520,10 @@ internal static partial class CollectionsMultiplyExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (u0.Value * multiplicator).ToUnit<R>() : null;
d1 = u1.HasValue ? (u1.Value * multiplicator).ToUnit<R>() : null;
d2 = u2.HasValue ? (u2.Value * multiplicator).ToUnit<R>() : null;
d3 = u3.HasValue ? (u3.Value * multiplicator).ToUnit<R>() : null;
d0 = ((u0 ?? 0d) * multiplicator).ToUnit<R>();
d1 = ((u1 ?? 0d) * multiplicator).ToUnit<R>();
d2 = ((u2 ?? 0d) * multiplicator).ToUnit<R>();
d3 = ((u3 ?? 0d) * multiplicator).ToUnit<R>();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -537,18 +532,18 @@ internal static partial class CollectionsMultiplyExtensions
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (unit.Value * multiplicator).ToUnit<R>() : null;
dst = ((unit ?? 0d) * multiplicator).ToUnit<R>();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MultiplyCore<R>(this double multiplicator, ReadOnlySpan<double> units,
int len, Span<R> destination) where R : struct, IMensuraUnit, IEquatable<R> => units.MultiplyCore(multiplicator, len, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MultiplyCore<R>(this double multiplicator, ReadOnlySpan<double?> units,
int len, Span<R?> destination) where R : struct, IMensuraUnit, IEquatable<R> => units.MultiplyCore(multiplicator, len, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MulCore<R>(this double multiplicator, ReadOnlySpan<double> units,
int len, Span<R> destination) where R : struct, IMensuraUnit, IEquatable<R> => units.MulCore(multiplicator, len, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MulCore<R>(this double multiplicator, ReadOnlySpan<double?> units,
int len, Span<R?> destination) where R : struct, IMensuraUnit, IEquatable<R> => units.MulCore(multiplicator, len, destination);
// === MultiplyCore === SIMD
internal static void MultiplyCore(this ReadOnlySpan<double> srcDouble, double multiplicator, int len, Span<double> dstDouble)
// === MulCore === SIMD
internal static void MulCore(this ReadOnlySpan<double> srcDouble, double multiplicator, int len, Span<double> dstDouble)
{
var vectorizedMultiplicator = new Vector<double>(multiplicator);
int vectorSize = Vector<double>.Count;
@@ -575,7 +570,7 @@ internal static partial class CollectionsMultiplyExtensions
Unsafe.Add(ref dstRef, i) = Unsafe.Add(ref srcRef, i) * multiplicator;
}
}
internal static void MultiplyCore(this ReadOnlySpan<double?> units, double multiplicator, int len, Span<double?> destination)
internal static void MulCore(this ReadOnlySpan<double?> units, double multiplicator, int len, Span<double?> destination)
{
// Получаем прямые неуправляемые ref-ссылки на начало буферов за 0 тактов
ref var srcRef = ref MemoryMarshal.GetReference(units);
@@ -599,10 +594,10 @@ internal static partial class CollectionsMultiplyExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? u0.Value * multiplicator : null;
d1 = u1.HasValue ? u1.Value * multiplicator : null;
d2 = u2.HasValue ? u2.Value * multiplicator : null;
d3 = u3.HasValue ? u3.Value * multiplicator : null;
d0 = (u0 ?? 0d) * multiplicator;
d1 = (u1 ?? 0d) * multiplicator;
d2 = (u2 ?? 0d) * multiplicator;
d3 = (u3 ?? 0d) * multiplicator;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -610,15 +605,14 @@ internal static partial class CollectionsMultiplyExtensions
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? unit.Value * multiplicator : null;
dst = (unit ?? 0d) * multiplicator;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MultiplyCore(this double multiplicator,
ReadOnlySpan<double> units, int len, Span<double> destination) => units.MultiplyCore(multiplicator, len, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MultiplyCore(this double multiplicator,
ReadOnlySpan<double?> units, int len, Span<double?> destination) => units.MultiplyCore(multiplicator, len, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MulCore(this double multiplicator,
ReadOnlySpan<double> units, int len, Span<double> destination) => units.MulCore(multiplicator, len, destination);
[MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MulCore(this double multiplicator,
ReadOnlySpan<double?> units, int len, Span<double?> destination) => units.MulCore(multiplicator, len, destination);
@@ -633,7 +627,7 @@ internal static partial class CollectionsMultiplyExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.MultiplyCore(multiplicator.ToDouble(), len, destination);
units.MulCore(multiplicator.ToDouble(), len, destination);
}
internal static void Mul<T>(this ReadOnlySpan<double?> units, T multiplicator, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -643,7 +637,7 @@ internal static partial class CollectionsMultiplyExtensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.MultiplyCore(multiplicator.ToDouble(), len, destination);
units.MulCore(multiplicator.ToDouble(), len, destination);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -663,7 +657,7 @@ internal static partial class CollectionsMultiplyExtensions
if (len == 0) return [];
var result = new T[len];
Mul(units, multiplicator, result);
units.MulCore(multiplicator.ToDouble(), len, result);
return result;
}
internal static T?[] Mul<T>(this double?[] units, T multiplicator)
@@ -674,7 +668,7 @@ internal static partial class CollectionsMultiplyExtensions
if (len == 0) return [];
var result = new T?[len];
Mul(units, multiplicator, result);
units.MulCore(multiplicator.ToDouble(), len, result);
return result;
}
@@ -691,12 +685,12 @@ internal static partial class CollectionsMultiplyExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[len];
Mul(CollectionsMarshal.AsSpan(units), multiplicator, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T[count];
CollectionsMarshal.AsSpan(units).MulCore(multiplicator.ToDouble(), count, result);
return result.WrapAsList<T, T>();
}
internal static List<T?> Mul<T>(this List<double?> units, T multiplicator)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -705,9 +699,9 @@ internal static partial class CollectionsMultiplyExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Mul(CollectionsMarshal.AsSpan(units), multiplicator, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T?[count];
CollectionsMarshal.AsSpan(units).MulCore(multiplicator.ToDouble(), count, result);
return result.WrapAsList<T, T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -728,12 +722,13 @@ internal static partial class CollectionsMultiplyExtensions
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; }
if (units is double[] array) { array.MulCore(multiplicator.ToDouble(), array.Length, destination); return; }
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).MulCore(multiplicator.ToDouble(), list.Count, destination); return; }
int i = 0;
var mul = multiplicator.ToDouble();
foreach (var item in units)
destination[i++] = (item * multiplicator.ToDouble()).ToUnit<T>();
destination[i++] = (item * mul).ToUnit<T>();
}
internal static void Mul<T>(this IReadOnlyCollection<double?> units, T multiplicator, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -744,13 +739,13 @@ internal static partial class CollectionsMultiplyExtensions
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; }
if (units is double?[] array) { array.MulCore(multiplicator.ToDouble(), array.Length, destination); return; }
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).MulCore(multiplicator.ToDouble(), list.Count, destination); return; }
int i = 0;
var mul = multiplicator.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value * multiplicator.ToDouble()).ToUnit<T>() : null;
destination[i++] = ((item ?? 0d) * mul).ToUnit<T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -772,8 +767,7 @@ internal static partial class CollectionsMultiplyExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (var item in units)
yield return item.HasValue
? (item.Value * multiplicator).ToUnit<T>() : null;
yield return ((item ?? 0d) * multiplicator).ToUnit<T>();
}
// === IEnumerable<T> ===
@@ -786,7 +780,7 @@ internal static partial class CollectionsMultiplyExtensions
if (units is IReadOnlyCollection<double> roc)
{
var arr = roc.ToArray();
arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr);
arr.MulCore(multiplicator.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
return MultiplyIterator<T>(units, multiplicator.ToDouble());
@@ -800,7 +794,7 @@ internal static partial class CollectionsMultiplyExtensions
if (units is IReadOnlyCollection<double?> roc)
{
var arr = roc.ToArray();
arr.MultiplyCore(multiplicator.ToDouble(), arr.Length, arr);
arr.MulCore(multiplicator.ToDouble(), arr.Length, arr);
return arr.ReCast<T>();
}
return MultiplyNullableIterator<T>(units, multiplicator.ToDouble());

View File

@@ -62,10 +62,10 @@ internal static partial class CollectionsPlusExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (u0.Value.ToDouble() + summand).ToUnit<R>() : null;
d1 = u1.HasValue ? (u1.Value.ToDouble() + summand).ToUnit<R>() : null;
d2 = u2.HasValue ? (u2.Value.ToDouble() + summand).ToUnit<R>() : null;
d3 = u3.HasValue ? (u3.Value.ToDouble() + summand).ToUnit<R>() : null;
d0 = (u0.Protected() + summand).ToUnit<R>();
d1 = (u1.Protected() + summand).ToUnit<R>();
d2 = (u2.Protected() + summand).ToUnit<R>();
d3 = (u3.Protected() + summand).ToUnit<R>();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -73,8 +73,7 @@ internal static partial class CollectionsPlusExtensions
{
T? unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (unit.Value.ToDouble() + summand).ToUnit<R>() : null;
dst = (unit.Protected() + summand).ToUnit<R>();
}
}
@@ -136,9 +135,9 @@ internal static partial class CollectionsPlusExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R[count];
PlusCore(CollectionsMarshal.AsSpan(units), summand, count, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R[count];
PlusCore(CollectionsMarshal.AsSpan(units), summand, count, result);
return result.WrapAsList<R, R>();
}
internal static List<R?> Plus<T, R>(this List<T?> units, double summand)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -148,9 +147,9 @@ internal static partial class CollectionsPlusExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R?[count];
PlusCore(CollectionsMarshal.AsSpan(units), summand, count, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R?[count];
PlusCore(CollectionsMarshal.AsSpan(units), summand, count, result);
return result.WrapAsList<R, R>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -196,8 +195,7 @@ internal static partial class CollectionsPlusExtensions
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value.ToDouble() + summand).ToUnit<R>() : null;
destination[i++] = (item.Protected() + summand).ToUnit<R>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -223,8 +221,7 @@ internal static partial class CollectionsPlusExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (T? item in units)
yield return item.HasValue
? (item.Value.ToDouble() + summand).ToUnit<R>() : null;
yield return (item.Protected() + summand).ToUnit<R>();
}
// === IEnumerable<T> ===
@@ -238,7 +235,7 @@ internal static partial class CollectionsPlusExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Plus(summand, arr);
arr.PlusCore(summand, arr.Length, arr);
return arr.ReCast<T, R>();
}
return PlusIterator<T, R>(units, summand);
@@ -253,7 +250,7 @@ internal static partial class CollectionsPlusExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Plus(summand, arr);
arr.PlusCore(summand, arr.Length, arr);
return arr.ReCast<T, R>();
}
return PlusNullableIterator<T, R>(units, summand);
@@ -311,7 +308,7 @@ internal static partial class CollectionsPlusExtensions
if (len == 0) return [];
var result = new T[len];
Plus(units, summand, result);
units.PlusCore(summand, len, result);
return result;
}
internal static T?[] Plus<T>(this T?[] units, double summand)
@@ -322,7 +319,7 @@ internal static partial class CollectionsPlusExtensions
if (len == 0) return [];
var result = new T?[len];
Plus(units, summand, result);
PlusCore(units, summand, len, result);
return result;
}
@@ -339,12 +336,12 @@ internal static partial class CollectionsPlusExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[len];
Plus(CollectionsMarshal.AsSpan(units), summand, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T[count];
CollectionsMarshal.AsSpan(units).PlusCore(summand, count, result);
return result.WrapAsList<T, T>();
}
internal static List<T?> Plus<T>(this List<T?> units, double summand)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -353,9 +350,9 @@ internal static partial class CollectionsPlusExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Plus(CollectionsMarshal.AsSpan(units), summand, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T?[count];
CollectionsMarshal.AsSpan(units).PlusCore(summand, count, result);
return result.WrapAsList<T, T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -376,8 +373,8 @@ internal static partial class CollectionsPlusExtensions
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; }
if (units is T[] array) { array.PlusCore(summand, count, destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).PlusCore(summand, count, destination); return; }
int i = 0;
foreach (var item in units)
@@ -392,13 +389,12 @@ internal static partial class CollectionsPlusExtensions
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; }
if (units is T?[] array) { array.PlusCore(summand, count, destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).PlusCore(summand, count, destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value.ToDouble() + summand).ToUnit<T>() : null;
destination[i++] = (item.Protected() + summand).ToUnit<T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -420,8 +416,7 @@ internal static partial class CollectionsPlusExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (T? item in units)
yield return item.HasValue
? (item.Value.ToDouble() + summand).ToUnit<T>() : null;
yield return (item.Protected() + summand).ToUnit<T>();
}
// === IEnumerable<T> ===
@@ -434,7 +429,7 @@ internal static partial class CollectionsPlusExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Plus(summand, arr);
arr.PlusCore(summand, arr.Length, arr);
return arr;
}
return PlusIterator(units, summand);
@@ -448,7 +443,7 @@ internal static partial class CollectionsPlusExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Plus(summand, arr);
arr.PlusCore(summand, arr.Length, arr);
return arr;
}
return PlusNullableIterator(units, summand);
@@ -526,10 +521,10 @@ internal static partial class CollectionsPlusExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? (u0.Value + summand).ToUnit<R>() : null;
d1 = u1.HasValue ? (u1.Value + summand).ToUnit<R>() : null;
d2 = u2.HasValue ? (u2.Value + summand).ToUnit<R>() : null;
d3 = u3.HasValue ? (u3.Value + summand).ToUnit<R>() : null;
d0 = ((u0 ?? 0d) + summand).ToUnit<R>();
d1 = ((u1 ?? 0d) + summand).ToUnit<R>();
d2 = ((u2 ?? 0d) + summand).ToUnit<R>();
d3 = ((u3 ?? 0d) + summand).ToUnit<R>();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -537,8 +532,7 @@ internal static partial class CollectionsPlusExtensions
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? (unit.Value + summand).ToUnit<R>() : null;
dst = ((unit ?? 0d) + summand).ToUnit<R>();
}
}
@@ -602,10 +596,10 @@ internal static partial class CollectionsPlusExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Пишем строго по месту. Если HasValue == false, в ячейку dX запишется null (сбросятся байты флага)
d0 = u0.HasValue ? u0.Value + summand : null;
d1 = u1.HasValue ? u1.Value + summand : null;
d2 = u2.HasValue ? u2.Value + summand : null;
d3 = u3.HasValue ? u3.Value + summand : null;
d0 = (u0 ?? 0d) + summand;
d1 = (u1 ?? 0d) + summand;
d2 = (u2 ?? 0d) + summand;
d3 = (u3 ?? 0d) + summand;
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 штук)
@@ -613,8 +607,7 @@ internal static partial class CollectionsPlusExtensions
{
var unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? unit.Value + summand : null;
dst = (unit ?? 0d) + summand;
}
}
@@ -668,7 +661,7 @@ internal static partial class CollectionsPlusExtensions
if (len == 0) return [];
var result = new T[len];
Plus(units, summand, result);
units.PlusCore(summand.ToDouble(), len, result);
return result;
}
internal static T?[] Plus<T>(this double?[] units, T summand)
@@ -679,7 +672,7 @@ internal static partial class CollectionsPlusExtensions
if (len == 0) return [];
var result = new T?[len];
Plus(units, summand, result);
units.PlusCore(summand.ToDouble(), len, result);
return result;
}
@@ -696,12 +689,12 @@ internal static partial class CollectionsPlusExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
int count = units.Count;
if (count == 0) return [];
var resultArray = new T[len];
Plus(CollectionsMarshal.AsSpan(units), summand, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T[count];
CollectionsMarshal.AsSpan(units).PlusCore(summand.ToDouble(), count, result);
return result.WrapAsList<T, T>();
}
internal static List<T?> Plus<T>(this List<double?> units, T summand)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -710,9 +703,9 @@ internal static partial class CollectionsPlusExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new T?[count];
Plus(CollectionsMarshal.AsSpan(units), summand, resultArray);
return resultArray.WrapAsList<T, T>();
var result = new T?[count];
CollectionsMarshal.AsSpan(units).PlusCore(summand.ToDouble(), count, result);
return result.WrapAsList<T, T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -737,8 +730,9 @@ internal static partial class CollectionsPlusExtensions
if (units is List<double> list) { CollectionsMarshal.AsSpan(list).PlusCore(summand.ToDouble(), list.Count, destination); return; }
int i = 0;
var sum = summand.ToDouble();
foreach (var item in units)
destination[i++] = (item + summand.ToDouble()).ToUnit<T>();
destination[i++] = (item + sum).ToUnit<T>();
}
internal static void Plus<T>(this IReadOnlyCollection<double?> units, T summand, Span<T?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -753,9 +747,9 @@ internal static partial class CollectionsPlusExtensions
if (units is List<double?> list) { CollectionsMarshal.AsSpan(list).PlusCore(summand.ToDouble(), list.Count, destination); return; }
int i = 0;
var sum = summand.ToDouble();
foreach (var item in units)
destination[i++] = item.HasValue
? (item.Value + summand.ToDouble()).ToUnit<T>() : null;
destination[i++] = ((item ?? 0d) + sum).ToUnit<T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -777,8 +771,7 @@ internal static partial class CollectionsPlusExtensions
where T : struct, IMensuraUnit, IEquatable<T>
{
foreach (var item in units)
yield return item.HasValue
? (item.Value + summand).ToUnit<T>() : null;
yield return ((item ?? 0d) + summand).ToUnit<T>();
}
// === IEnumerable<T> ===

View File

@@ -130,7 +130,7 @@ internal static partial class CollectionsPow2Extensions
if (len == 0) return [];
var result = new R[len];
Pow2(units, result);
units.Pow2Core(len, result);
return result;
}
internal static R?[] Pow2<T, R>(this T?[] units)
@@ -142,7 +142,7 @@ internal static partial class CollectionsPow2Extensions
if (len == 0) return [];
var result = new R?[len];
Pow2(units, result);
units.Pow2Core(len, result);
return result;
}
@@ -155,9 +155,9 @@ internal static partial class CollectionsPow2Extensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R[count];
Pow2(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R[count];
CollectionsMarshal.AsSpan(units).Pow2Core(count, result);
return result.WrapAsList<R, R>();
}
internal static List<R?> Pow2<T, R>(this List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -167,9 +167,9 @@ internal static partial class CollectionsPow2Extensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R?[count];
Pow2(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R?[count];
CollectionsMarshal.AsSpan(units).Pow2Core(count, result);
return result.WrapAsList<R, R>();
}
// === IReadOnlyCollection<Length> ===
@@ -183,8 +183,8 @@ internal static partial class CollectionsPow2Extensions
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; }
if (units is T[] array) { array.Pow2Core(count, destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow2Core(count, destination); return; }
int i = 0;
foreach (var item in units)
@@ -200,13 +200,12 @@ internal static partial class CollectionsPow2Extensions
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; }
if (units is T?[] array) { array.Pow2Core(count, destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow2Core(count, destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? item.Value.ToDouble().QuickPow2().ToUnit<R>() : null;
destination[i++] = item.Protected().QuickPow2().ToUnit<R>();
}
// === IEnumerable<T, R> + yeild ===
@@ -222,8 +221,7 @@ internal static partial class CollectionsPow2Extensions
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (var item in units)
yield return item.HasValue
? item.Value.ToDouble().QuickPow2().ToUnit<R>() : null;
yield return item.Protected().QuickPow2().ToUnit<R>();
}
// === IEnumerable<Length> ===
@@ -237,7 +235,7 @@ internal static partial class CollectionsPow2Extensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Pow2(arr);
arr.Pow2Core(arr.Length, arr);
return arr.ReCast<T, R>();
}
else return Pow2Iterator<T, R>(units);
@@ -252,7 +250,7 @@ internal static partial class CollectionsPow2Extensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Pow2(arr);
arr.Pow2Core(arr.Length, arr);
return arr.ReCast<T, R>();
}
else return Pow2NullableIterator<T, R>(units);

View File

@@ -1,7 +1,4 @@
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace QWERTYkez.Mensura.Extensions;
namespace QWERTYkez.Mensura.Extensions;
internal static partial class CollectionsPow3Extensions
{
@@ -10,8 +7,8 @@ internal static partial class CollectionsPow3Extensions
// === ТРЕТЬЯ СТЕПЕНЬ ==========================================
// === PowCore3 === SIMD
internal static void PowCore3<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
// === Pow3Core === SIMD
internal static void Pow3Core<T, R>(this ReadOnlySpan<T> units, int len, Span<R> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
@@ -46,7 +43,7 @@ internal static partial class CollectionsPow3Extensions
dstDouble[i] = val * val * val;
}
}
internal static void PowCore3<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
internal static void Pow3Core<T, R>(this ReadOnlySpan<T?> units, int len, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
where R : struct, IMensuraUnit, IEquatable<R>
{
@@ -109,7 +106,7 @@ internal static partial class CollectionsPow3Extensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.PowCore3(len, destination);
units.Pow3Core(len, destination);
}
internal static void Pow3<T, R>(this ReadOnlySpan<T?> units, Span<R?> destination)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -120,7 +117,7 @@ internal static partial class CollectionsPow3Extensions
if (len > destination.Length)
throw new ArgumentException("Целевой буфер destination меньше исходного source.");
units.PowCore3(len, destination);
units.Pow3Core(len, destination);
}
// === Array ===
@@ -133,7 +130,7 @@ internal static partial class CollectionsPow3Extensions
if (len == 0) return [];
var result = new R[len];
Pow3(units, result);
units.Pow3Core(len, result);
return result;
}
internal static R?[] Pow3<T, R>(this T?[] units)
@@ -145,7 +142,7 @@ internal static partial class CollectionsPow3Extensions
if (len == 0) return [];
var result = new R?[len];
Pow3(units, result);
units.Pow3Core(len, result);
return result;
}
@@ -158,9 +155,9 @@ internal static partial class CollectionsPow3Extensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R[count];
Pow3(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R[count];
CollectionsMarshal.AsSpan(units).Pow3Core(count, result);
return result.WrapAsList<R, R>();
}
internal static List<R?> Pow3<T, R>(this List<T?> units)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -170,9 +167,9 @@ internal static partial class CollectionsPow3Extensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R?[count];
Pow3(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R?[count];
CollectionsMarshal.AsSpan(units).Pow3Core(count, result);
return result.WrapAsList<R, R>();
}
// === IReadOnlyCollection<Length> ===
@@ -186,8 +183,8 @@ internal static partial class CollectionsPow3Extensions
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; }
if (units is T[] array) { array.Pow3Core(count, destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).Pow3Core(count, destination); return; }
int i = 0;
foreach (var item in units)
@@ -203,13 +200,12 @@ internal static partial class CollectionsPow3Extensions
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; }
if (units is T?[] array) { array.Pow3Core(count, destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).Pow3Core(count, destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? item.Value.ToDouble().QuickPow3().ToUnit<R>() : null;
destination[i++] = item.Protected().QuickPow3().ToUnit<R>();
}
// === IEnumerable<T, R> + yeild ===
@@ -225,8 +221,7 @@ internal static partial class CollectionsPow3Extensions
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (var item in units)
yield return item.HasValue
? item.Value.ToDouble().QuickPow3().ToUnit<R>() : null;
yield return item.Protected().QuickPow3().ToUnit<R>();
}
// === IEnumerable<Length> ===
@@ -240,7 +235,7 @@ internal static partial class CollectionsPow3Extensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Pow3(arr);
arr.Pow3Core(arr.Length, arr);
return arr.ReCast<T, R>();
}
else return PowIterator3<T, R>(units);
@@ -255,7 +250,7 @@ internal static partial class CollectionsPow3Extensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Pow3(arr);
arr.Pow3Core(arr.Length, arr);
return arr.ReCast<T, R>();
}
else return PowNullableIterator3<T, R>(units);

View File

@@ -129,10 +129,10 @@ internal static partial class CollectionsPowNExtensions
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
// Выполняем быструю бинарную математику и трансформируем тип из T в R по месту
d0 = u0.HasValue ? u0.Value.ToDouble().QuickPow(power).ToUnit<R>() : null;
d1 = u1.HasValue ? u1.Value.ToDouble().QuickPow(power).ToUnit<R>() : null;
d2 = u2.HasValue ? u2.Value.ToDouble().QuickPow(power).ToUnit<R>() : null;
d3 = u3.HasValue ? u3.Value.ToDouble().QuickPow(power).ToUnit<R>() : null;
d0 = u0.Protected().QuickPow(power).ToUnit<R>();
d1 = u1.Protected().QuickPow(power).ToUnit<R>();
d2 = u2.Protected().QuickPow(power).ToUnit<R>();
d3 = u3.Protected().QuickPow(power).ToUnit<R>();
}
// 2. ХВОСТ ЦИКЛА: Довычисляем остаток элементов (от 1 до 3 шчку)
@@ -141,7 +141,7 @@ internal static partial class CollectionsPowNExtensions
T? unit = Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? unit.Value.ToDouble().QuickPow(power).ToUnit<R>() : null;
dst = unit.Protected().QuickPow(power).ToUnit<R>();
}
}
@@ -180,7 +180,7 @@ internal static partial class CollectionsPowNExtensions
if (len == 0) return [];
var result = new R[len];
Pow(units, power, result);
units.PowCore(power, len, result);
return result;
}
internal static R?[] Pow<T, R>(this T?[] units, int power)
@@ -192,7 +192,7 @@ internal static partial class CollectionsPowNExtensions
if (len == 0) return [];
var result = new R?[len];
Pow(units, power, result);
units.PowCore(power, len, result);
return result;
}
@@ -205,9 +205,9 @@ internal static partial class CollectionsPowNExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R[count];
Pow(CollectionsMarshal.AsSpan(units), power, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R[count];
CollectionsMarshal.AsSpan(units).PowCore(power, count, result);
return result.WrapAsList<R, R>();
}
internal static List<R?> Pow<T, R>(this List<T?> units, int power)
where T : struct, IMensuraUnit, IEquatable<T>
@@ -217,9 +217,9 @@ internal static partial class CollectionsPowNExtensions
int count = units.Count;
if (count == 0) return [];
var resultArray = new R?[count];
Pow(CollectionsMarshal.AsSpan(units), power, resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R?[count];
CollectionsMarshal.AsSpan(units).PowCore(power, count, result);
return result.WrapAsList<R, R>();
}
// === IReadOnlyCollection<Length> ===
@@ -233,8 +233,8 @@ internal static partial class CollectionsPowNExtensions
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; }
if (units is T[] array) { array.PowCore(power, count, destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).PowCore(power, count, destination); return; }
int i = 0;
foreach (var item in units)
@@ -250,13 +250,12 @@ internal static partial class CollectionsPowNExtensions
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; }
if (units is T?[] array) { array.PowCore(power, count, destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).PowCore(power, count, destination); return; }
int i = 0;
foreach (var item in units)
destination[i++] = item.HasValue
? item.Value.ToDouble().QuickPow(power).ToUnit<R>() : null;
destination[i++] = item.Protected().QuickPow(power).ToUnit<R>();
}
// === IEnumerable<T, R> + yeild ===
@@ -272,8 +271,7 @@ internal static partial class CollectionsPowNExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (var item in units)
yield return item.HasValue
? item.Value.ToDouble().QuickPow(power).ToUnit<R>() : null;
yield return item.Protected().QuickPow(power).ToUnit<R>();
}
// === IEnumerable<Length> ===
@@ -287,7 +285,7 @@ internal static partial class CollectionsPowNExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Pow(power, arr);
arr.PowCore(power, arr.Length, arr);
return arr.ReCast<T, R>();
}
else return PowIterator<T, R>(units, power);
@@ -302,7 +300,7 @@ internal static partial class CollectionsPowNExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Pow(power, arr);
arr.PowCore(power, arr.Length, arr);
return arr.ReCast<T, R>();
}
else return PowNullableIterator<T, R>(units, power);
@@ -402,7 +400,7 @@ internal static partial class CollectionsPowNExtensions
{
// Прямая ref-запись в переданный снаружи destination
ref var dst = ref destination[i];
dst = Math.Pow(item.Value.ToDouble(), power).ToUnit<R>();
dst = Math.Pow(item.Protected(), power).ToUnit<R>();
}
}
}
@@ -443,7 +441,7 @@ internal static partial class CollectionsPowNExtensions
if (len == 0) return [];
var result = new R[len];
units.Pow(power, result);
units.PowCore(power, len, result);
return result;
}
internal static R?[] Pow<T, R>(this T?[] units, double power)
@@ -455,7 +453,7 @@ internal static partial class CollectionsPowNExtensions
if (len == 0) return [];
var result = new R?[len];
units.Pow(power, result);
units.PowCore(power, len, result);
return result;
}
@@ -465,11 +463,11 @@ internal static partial class CollectionsPowNExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
int count = units.Count;
if (count == 0) return [];
var result = new R[len];
CollectionsMarshal.AsSpan(units).Pow(power, result);
var result = new R[count];
CollectionsMarshal.AsSpan(units).PowCore(power, count, result);
return result.WrapAsList<R, R>();
}
internal static List<R?> Pow<T, R>(this List<T?> units, double power)
@@ -477,11 +475,11 @@ internal static partial class CollectionsPowNExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
int count = units.Count;
if (count == 0) return [];
var result = new R?[len];
CollectionsMarshal.AsSpan(units).Pow(power, result);
var result = new R?[count];
CollectionsMarshal.AsSpan(units).PowCore(power, count, result);
return result.WrapAsList<R, R>();
}
@@ -496,8 +494,8 @@ internal static partial class CollectionsPowNExtensions
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; }
if (units is T[] array) { array.PowCore(power, count, destination); return; }
if (units is List<T> list) { CollectionsMarshal.AsSpan(list).PowCore(power, count, destination); return; }
int i = 0;
foreach (T item in units)
@@ -513,13 +511,12 @@ internal static partial class CollectionsPowNExtensions
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; }
if (units is T?[] array) { array.PowCore(power, count, destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).PowCore(power, count, destination); return; }
int i = 0;
foreach (T? item in units)
destination[i++] = item.HasValue
? Math.Pow(item.Value.ToDouble(), power).ToUnit<R>() : null;
destination[i++] = Math.Pow(item.Protected(), power).ToUnit<R>();
}
// === IEnumerable<Length> + yield ===
@@ -535,8 +532,7 @@ internal static partial class CollectionsPowNExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (var item in units)
yield return item.HasValue
? Math.Pow(item.Value.ToDouble(), power).ToUnit<R>() : null;
yield return Math.Pow(item.Protected(), power).ToUnit<R>();
}
// === IEnumerable<Length> ===
@@ -550,7 +546,7 @@ internal static partial class CollectionsPowNExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Pow(power, arr);
arr.PowCore(power, arr.Length, arr);
return arr.ReCast<T, R>();
}
else return PowIterator<T, R>(units, power);
@@ -565,7 +561,7 @@ internal static partial class CollectionsPowNExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Pow(power, arr);
arr.PowCore(power, arr.Length, arr);
return arr.ReCast<T, R>();
}
else return PowNullableIterator<T, R>(units, power);

View File

@@ -46,13 +46,13 @@ internal static partial class CollectionsRootOfCubeExtensions
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;
Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i)!.Protected()).ToUnit<R>();
Unsafe.Add(ref dstRef, i + 1) = Math.Sqrt(Unsafe.Add(ref srcRef, i + 1)!.Protected()).ToUnit<R>();
Unsafe.Add(ref dstRef, i + 2) = Math.Sqrt(Unsafe.Add(ref srcRef, i + 2)!.Protected()).ToUnit<R>();
Unsafe.Add(ref dstRef, i + 3) = Math.Sqrt(Unsafe.Add(ref srcRef, i + 3)!.Protected()).ToUnit<R>();
}
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;
Unsafe.Add(ref dstRef, i) = Math.Sqrt(Unsafe.Add(ref srcRef, i)!.Protected()).ToUnit<R>();
}
// === ReadOnlySpan ===
@@ -85,10 +85,11 @@ internal static partial class CollectionsRootOfCubeExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
if (units.Length == 0) return [];
var len = units.Length;
if (len == 0) return [];
var result = new R[units.Length];
Cbrt(units, result);
var result = new R[len];
units.CbrtCore(len, result);
return result;
}
internal static R?[] Cbrt<T, R>(this T?[] units)
@@ -96,10 +97,11 @@ internal static partial class CollectionsRootOfCubeExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
if (units.Length == 0) return [];
var len = units.Length;
if (len == 0) return [];
var result = new R?[units.Length];
Cbrt(units, result);
var result = new R?[len];
units.CbrtCore(len, result);
return result;
}
@@ -109,24 +111,24 @@ internal static partial class CollectionsRootOfCubeExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
int count = units.Count;
if (count == 0) return [];
var resultArray = new R[len];
Cbrt(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R[count];
CollectionsMarshal.AsSpan(units).CbrtCore(count, result);
return result.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 [];
int count = units.Count;
if (count == 0) return [];
var resultArray = new R?[len];
Cbrt(CollectionsMarshal.AsSpan(units), resultArray);
return resultArray.WrapAsList<R, R>();
var result = new R?[count];
CollectionsMarshal.AsSpan(units).CbrtCore(count, result);
return result.WrapAsList<R, R>();
}
// === IReadOnlyCollection ===
@@ -156,13 +158,12 @@ internal static partial class CollectionsRootOfCubeExtensions
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; }
if (units is T?[] array) { array.CbrtCore(count, destination); return; }
if (units is List<T?> list) { CollectionsMarshal.AsSpan(list).CbrtCore(count, destination); return; }
int i = 0;
foreach (T? item in units)
destination[i++] = item.HasValue
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
destination[i++] = Math.Sqrt(item.Protected()).ToUnit<R>();
}
// === IEnumerable + yield ===
@@ -177,8 +178,7 @@ internal static partial class CollectionsRootOfCubeExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (var item in units)
yield return item.HasValue
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
yield return Math.Sqrt(item.Protected()).ToUnit<R>();
}
// === IEnumerable ===
@@ -192,7 +192,7 @@ internal static partial class CollectionsRootOfCubeExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Cbrt(arr);
arr.CbrtCore(arr.Length, arr);
return arr.ReCast<T, R>();
}
else return SqrtIterator3<T, R>(units);
@@ -207,7 +207,7 @@ internal static partial class CollectionsRootOfCubeExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Cbrt(arr);
arr.CbrtCore(arr.Length, arr);
return arr.ReCast<T, R>();
}
else return SqrtNullableIterator3<T, R>(units);

View File

@@ -77,10 +77,10 @@ internal static partial class CollectionsRootOfSquareExtensions
ref var d2 = ref Unsafe.Add(ref dstRef, i + 2);
ref var d3 = ref Unsafe.Add(ref dstRef, i + 3);
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;
d0 = Math.Sqrt(u0.Protected()).ToUnit<R>();
d1 = Math.Sqrt(u1.Protected()).ToUnit<R>();
d2 = Math.Sqrt(u2.Protected()).ToUnit<R>();
d3 = Math.Sqrt(u3.Protected()).ToUnit<R>();
}
// ХВОСТ ЦИКЛА: Остаток элементов
@@ -88,7 +88,7 @@ internal static partial class CollectionsRootOfSquareExtensions
{
ref readonly T? unit = ref Unsafe.Add(ref srcRef, i);
ref var dst = ref Unsafe.Add(ref dstRef, i);
dst = unit.HasValue ? Math.Sqrt(unit.Value.ToDouble()).ToUnit<R>() : null;
dst = Math.Sqrt(unit.Protected()).ToUnit<R>();
}
}
@@ -146,24 +146,24 @@ internal static partial class CollectionsRootOfSquareExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
if (units is null) return null!;
int len = units.Count;
if (len == 0) return [];
int count = units.Count;
if (count == 0) return [];
var resultArray = new R[len];
CollectionsMarshal.AsSpan(units).SqrtCore(len, resultArray.AsSpan());
return resultArray.WrapAsList<R, R>();
var result = new R[count];
CollectionsMarshal.AsSpan(units).SqrtCore(count, result.AsSpan());
return result.WrapAsList<R, R>();
}
internal static List<R?> Sqrt<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 [];
int count = units.Count;
if (count == 0) return [];
var resultArray = new R?[len];
CollectionsMarshal.AsSpan(units).SqrtCore(len, resultArray.AsSpan());
return resultArray.WrapAsList<R, R>();
var result = new R?[count];
CollectionsMarshal.AsSpan(units).SqrtCore(count, result.AsSpan());
return result.WrapAsList<R, R>();
}
// === IReadOnlyCollection ===
@@ -206,8 +206,7 @@ internal static partial class CollectionsRootOfSquareExtensions
foreach (T? item in units)
{
if ((uint)i >= (uint)count) break;
Unsafe.Add(ref dstRef, i++) = item.HasValue
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
Unsafe.Add(ref dstRef, i++) = Math.Sqrt(item.Protected()).ToUnit<R>();
}
}
@@ -224,8 +223,7 @@ internal static partial class CollectionsRootOfSquareExtensions
where R : struct, IMensuraUnit, IEquatable<R>
{
foreach (var item in units)
yield return item.HasValue
? Math.Sqrt(item.Value.ToDouble()).ToUnit<R>() : null;
yield return Math.Sqrt(item.Protected()).ToUnit<R>();
}
// === IEnumerable API ===
@@ -239,7 +237,7 @@ internal static partial class CollectionsRootOfSquareExtensions
if (units is IReadOnlyCollection<T> roc)
{
var arr = roc.ToArray();
arr.Sqrt(arr);
arr.SqrtCore(arr.Length, arr);
return arr.ReCast<T, R>();
}
else return SqrtIterator<T, R>(units);
@@ -254,7 +252,7 @@ internal static partial class CollectionsRootOfSquareExtensions
if (units is IReadOnlyCollection<T?> roc)
{
var arr = roc.ToArray();
arr.Sqrt(arr);
arr.SqrtCore(arr.Length, arr);
return arr.ReCast<T, R>();
}
else return SqrtNullableIterator<T, R>(units);

View File

@@ -16,18 +16,18 @@ internal static partial class DoubleExtensions
internal static double ToDouble(this float number) => number;
internal static double ToDouble(this decimal number) => (double)number;
internal static double ToDouble(this byte? number) => number.HasValue ? number.Value : 0d;
internal static double ToDouble(this sbyte? number) => number.HasValue ? number.Value : 0d;
internal static double ToDouble(this short? number) => number.HasValue ? number.Value : 0d;
internal static double ToDouble(this ushort? number) => number.HasValue ? number.Value : 0d;
internal static double ToDouble(this int? number) => number.HasValue ? number.Value : 0d;
internal static double ToDouble(this uint? number) => number.HasValue ? number.Value : 0d;
internal static double ToDouble(this nint? number) => number.HasValue ? number.Value : 0d;
internal static double ToDouble(this nuint? number) => number.HasValue ? number.Value : 0d;
internal static double ToDouble(this long? number) => number.HasValue ? number.Value : 0d;
internal static double ToDouble(this ulong? number) => number.HasValue ? number.Value : 0d;
internal static double ToDouble(this byte? number) => number ?? 0d;
internal static double ToDouble(this sbyte? number) => number ?? 0d;
internal static double ToDouble(this short? number) => number ?? 0d;
internal static double ToDouble(this ushort? number) => number ?? 0d;
internal static double ToDouble(this int? number) => number ?? 0d;
internal static double ToDouble(this uint? number) => number ?? 0d;
internal static double ToDouble(this nint? number) => number ?? 0d;
internal static double ToDouble(this nuint? number) => number ?? 0d;
internal static double ToDouble(this long? number) => number ?? 0d;
internal static double ToDouble(this ulong? number) => number ?? 0d;
internal static double ToDouble(this Half? number) => number.HasValue ? (double)number.Value : 0d;
internal static double ToDouble(this float? number) => number.HasValue ? number.Value : 0d;
internal static double ToDouble(this float? number) => number ?? 0d;
internal static double ToDouble(this decimal? number) => number.HasValue ? (double)number.Value : 0d;
#if NET7_0_OR_GREATER
@@ -1432,12 +1432,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)u.Value : null; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1451,12 +1451,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)u.Value : null; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1470,12 +1470,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)u.Value : null; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1489,12 +1489,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)u.Value : null; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1508,12 +1508,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)u.Value : null; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1527,12 +1527,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)u.Value : null; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1546,12 +1546,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)u.Value : null; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1565,12 +1565,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)u.Value : null; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1584,12 +1584,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)u.Value : null; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1603,12 +1603,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)u.Value : null; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1622,12 +1622,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)(double)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)(double)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)(double)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)(double)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)(double)u.Value : null; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1641,12 +1641,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)(double)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)(double)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)(double)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)(double)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)(double)u.Value : null; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1660,12 +1660,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)(double)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)(double)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)(double)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)(double)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)(double)u.Value : null; }
}
#if NET7_0_OR_GREATER
@@ -1680,12 +1680,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)(double)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)(double)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)(double)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)(double)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)(double)u.Value : null; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -1699,12 +1699,12 @@ internal static partial class DoubleExtensions
{
var u0 = Unsafe.Add(ref srcRef, i); var u1 = Unsafe.Add(ref srcRef, i + 1);
var u2 = Unsafe.Add(ref srcRef, i + 2); var u3 = Unsafe.Add(ref srcRef, i + 3);
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double)u0.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double)u1.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double)u2.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double)u3.GetValueOrDefault() : null;
Unsafe.Add(ref dstRef, i) = u0.HasValue ? (double?)(double)u0.Value : null;
Unsafe.Add(ref dstRef, i + 1) = u1.HasValue ? (double?)(double)u1.Value : null;
Unsafe.Add(ref dstRef, i + 2) = u2.HasValue ? (double?)(double)u2.Value : null;
Unsafe.Add(ref dstRef, i + 3) = u3.HasValue ? (double?)(double)u3.Value : null;
}
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double)u.GetValueOrDefault() : null; }
for (; i < len; i++) { var u = Unsafe.Add(ref srcRef, i); Unsafe.Add(ref dstRef, i) = u.HasValue ? (double?)(double)u.Value : null; }
}
#endif

View File

@@ -0,0 +1,20 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace QWERTYkez.Mensura.Extensions;
public static partial class EFCoreExtension
{
/// <summary>
/// Регистрирует ValueConverter для всех типов, реализующих IMensuraUnit.
/// </summary>
public static void UseMensuraUnits(this ModelConfigurationBuilder configurationBuilder)
{
AddGeneratedConverters(configurationBuilder);
AddGeneratedComplexConverters(configurationBuilder);
}
internal class MensuraUnitConverter<U>()
: ValueConverter<U, double>(unit => unit.ToDouble(), value => value.ToUnit<U>())
where U : struct, IMensuraUnit, IEquatable<U> { }
}

View File

@@ -9,7 +9,7 @@ internal class ListMimic<T>
}
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct NullableDoubleMimic
internal struct NullableDoubleMimic
{
[FieldOffset(0)] public bool HasValue;
[FieldOffset(8)] public double Value;

View File

@@ -10,10 +10,18 @@
<NoWarn>1701;1702;IDE1006</NoWarn>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\QWERTYkez.Mensura.Generator\QWERTYkez.Mensura.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<InternalsVisibleTo Include="QWERTYkez.Mensura.Tests" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" PrivateAssets="All" />
<ProjectReference Include="..\QWERTYkez.Mensura.Generator\QWERTYkez.Mensura.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<InternalsVisibleTo Include="QWERTYkez.Mensura.Tests" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.36" Condition="'$(TargetFramework)' == 'net6.0'" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.20" Condition="'$(TargetFramework)' == 'net7.0'" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.28" Condition="'$(TargetFramework)' == 'net8.0'" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.17" Condition="'$(TargetFramework)' == 'net9.0'" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.9" Condition="'$(TargetFramework)' == 'net10.0'" PrivateAssets="All" />
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -1,70 +1,70 @@
#if DEBUG
namespace QWERTYkez.Mensura.Units;
//#if DEBUG
//namespace QWERTYkez.Mensura.Units;
/// <summary>
/// Base value is MilliMeters
/// </summary>
[DebuggerDisplay("mm = {_MilliMeters.ToString(\"0.###\")}, m = {Meters.ToString(\"0.###\")}")]
public readonly partial record struct XXXXXXXX
{
public static XXXXXXXX MilliMeter { get; } = new(1);
[NotMapped, JsonIgnore, IgnoreDataMember] public double _MilliMeters { get => _Value; init => _Value = value; }
///// <summary>
///// Base value is MilliMeters
///// </summary>
//[DebuggerDisplay("mm = {_MilliMeters.ToString(\"0.###\")}, m = {Meters.ToString(\"0.###\")}")]
//public readonly partial record struct XXXXXXXX
//{
// public static XXXXXXXX MilliMeter { get; } = new(1);
// [NotMapped, JsonIgnore, IgnoreDataMember] public double _MilliMeters { get => _Value; init => _Value = value; }
public static XXXXXXXX CentiMeter { get; } = new(XXXXXXXXConv.CentiMeters.To(1));
[NotMapped, JsonIgnore, IgnoreDataMember]
public double CentiMeters
{
get => XXXXXXXXConv.CentiMeters.From(_Value);
init
{
_Value = XXXXXXXXConv.CentiMeters.To(value);
}
}
// public static XXXXXXXX CentiMeter { get; } = new(XXXXXXXXConv.CentiMeters.To(1));
// [NotMapped, JsonIgnore, IgnoreDataMember]
// public double CentiMeters
// {
// get => XXXXXXXXConv.CentiMeters.From(_Value);
// init
// {
// _Value = XXXXXXXXConv.CentiMeters.To(value);
// }
// }
public static XXXXXXXX DeciMeter { get; } = new(XXXXXXXXConv.DeciMeters.To(1));
[NotMapped, JsonIgnore, IgnoreDataMember]
public double DeciMeters
{
get => XXXXXXXXConv.DeciMeters.From(_Value);
init => _Value = XXXXXXXXConv.DeciMeters.To(value);
}
// public static XXXXXXXX DeciMeter { get; } = new(XXXXXXXXConv.DeciMeters.To(1));
// [NotMapped, JsonIgnore, IgnoreDataMember]
// public double DeciMeters
// {
// get => XXXXXXXXConv.DeciMeters.From(_Value);
// init => _Value = XXXXXXXXConv.DeciMeters.To(value);
// }
public static XXXXXXXX Meter { get; } = new(XXXXXXXXConv.Meters.To(1));
[NotMapped, JsonIgnore, IgnoreDataMember]
public double Meters
{
get => XXXXXXXXConv.Meters.From(_Value);
init => _Value = XXXXXXXXConv.Meters.To(value);
}
// public static XXXXXXXX Meter { get; } = new(XXXXXXXXConv.Meters.To(1));
// [NotMapped, JsonIgnore, IgnoreDataMember]
// public double Meters
// {
// get => XXXXXXXXConv.Meters.From(_Value);
// init => _Value = XXXXXXXXConv.Meters.To(value);
// }
public static XXXXXXXX KiloMeter { get; } = new(XXXXXXXXConv.KiloMeters.To(1));
[NotMapped, JsonIgnore, IgnoreDataMember]
public double KiloMeters
{
get => XXXXXXXXConv.KiloMeters.From(_Value);
init => _Value = XXXXXXXXConv.KiloMeters.To(value);
}
// public static XXXXXXXX KiloMeter { get; } = new(XXXXXXXXConv.KiloMeters.To(1));
// [NotMapped, JsonIgnore, IgnoreDataMember]
// public double KiloMeters
// {
// get => XXXXXXXXConv.KiloMeters.From(_Value);
// init => _Value = XXXXXXXXConv.KiloMeters.To(value);
// }
public XXXXXXXX AddMilliMeters(double value) => new(_Value + value);
public XXXXXXXX AddCentiMeters(double value) => new(_Value + XXXXXXXXConv.CentiMeters.To(value));
public XXXXXXXX AddDeciMeters(double value) => new(_Value + XXXXXXXXConv.DeciMeters.To(value));
public XXXXXXXX AddMeters(double value) => new(_Value + XXXXXXXXConv.Meters.To(value));
public XXXXXXXX AddKiloMeters(double value) => new(_Value + XXXXXXXXConv.KiloMeters.To(value));
}
// public XXXXXXXX AddMilliMeters(double value) => new(_Value + value);
// public XXXXXXXX AddCentiMeters(double value) => new(_Value + XXXXXXXXConv.CentiMeters.To(value));
// public XXXXXXXX AddDeciMeters(double value) => new(_Value + XXXXXXXXConv.DeciMeters.To(value));
// public XXXXXXXX AddMeters(double value) => new(_Value + XXXXXXXXConv.Meters.To(value));
// public XXXXXXXX AddKiloMeters(double value) => new(_Value + XXXXXXXXConv.KiloMeters.To(value));
//}
internal readonly struct XXXXXXXXConv
{
private XXXXXXXXConv(double multiplicator) => this.Multiplicator = multiplicator;
public double To(double value) => value * Multiplicator;
public double From(double value) => value / Multiplicator;
public double Multiplicator { get; init; }
public static XXXXXXXXConv MilliMeters { get; } = new(1);
public static XXXXXXXXConv CentiMeters { get; } = new(10);
public static XXXXXXXXConv DeciMeters { get; } = new(100);
public static XXXXXXXXConv Meters { get; } = new(1000);
public static XXXXXXXXConv KiloMeters { get; } = new(1000000);
}
#endif
//internal readonly struct XXXXXXXXConv
//{
// private XXXXXXXXConv(double multiplicator) => this.Multiplicator = multiplicator;
// public double To(double value) => value * Multiplicator;
// public double From(double value) => value / Multiplicator;
// public double Multiplicator { get; init; }
// public static XXXXXXXXConv MilliMeters { get; } = new(1);
// public static XXXXXXXXConv CentiMeters { get; } = new(10);
// public static XXXXXXXXConv DeciMeters { get; } = new(100);
// public static XXXXXXXXConv Meters { get; } = new(1000);
// public static XXXXXXXXConv KiloMeters { get; } = new(1000000);
//}
//#endif