mirror of
https://github.com/AlexMacocian/SystemExtensions.git
synced 2026-07-16 14:39:28 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f92b84d47 |
-129
@@ -1,129 +0,0 @@
|
||||
[*.{cs,vb}]
|
||||
|
||||
# IDE0003: Remove qualification
|
||||
dotnet_diagnostic.IDE0003.severity = error
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
tab_width = 4
|
||||
indent_size = 4
|
||||
end_of_line = crlf
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:error
|
||||
dotnet_style_prefer_auto_properties = true:error
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_compound_assignment = true:suggestion
|
||||
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||
dotnet_style_namespace_match_folder = true:suggestion
|
||||
|
||||
[*.cs]
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_using_directive_placement = outside_namespace:error
|
||||
csharp_prefer_simple_using_statement = true:error
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_style_namespace_declarations = file_scoped:error
|
||||
csharp_style_prefer_method_group_conversion = true:silent
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_constructors = false:silent
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_properties = true:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_accessors = true:silent
|
||||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_prefer_null_check_over_type_check = true:suggestion
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
csharp_style_prefer_local_over_anonymous_function = true:error
|
||||
csharp_style_prefer_index_operator = true:suggestion
|
||||
csharp_style_prefer_range_operator = true:suggestion
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
|
||||
csharp_style_prefer_tuple_swap = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
csharp_style_deconstructed_variable_declaration = true:error
|
||||
csharp_style_unused_value_assignment_preference = discard_variable:error
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
||||
csharp_prefer_static_local_function = true:suggestion
|
||||
csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
|
||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:suggestion
|
||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
csharp_style_prefer_parameter_null_checking = true:suggestion
|
||||
csharp_style_prefer_switch_expression = true:suggestion
|
||||
csharp_style_prefer_pattern_matching = true:silent
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_prefer_not_pattern = true:suggestion
|
||||
csharp_style_prefer_extended_property_pattern = true:suggestion
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
[*.{cs,vb}]
|
||||
#### Naming styles ####
|
||||
|
||||
# Naming rules
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# Symbol specifications
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
|
||||
dotnet_style_predefined_type_for_member_access = true:silent
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
|
||||
dotnet_style_allow_multiple_blank_lines_experimental = true:silent
|
||||
dotnet_style_allow_statement_immediately_after_block_experimental = false:suggestion
|
||||
dotnet_code_quality_unused_parameters = all:error
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
|
||||
dotnet_style_qualification_for_field = true:error
|
||||
dotnet_style_qualification_for_property = true:error
|
||||
dotnet_style_qualification_for_method = true:error
|
||||
dotnet_style_qualification_for_event = true:error
|
||||
@@ -1 +0,0 @@
|
||||
* amacocian@yahoo.com
|
||||
@@ -1,16 +0,0 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "nuget"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
+16
-38
@@ -4,7 +4,10 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
@@ -17,23 +20,21 @@ jobs:
|
||||
|
||||
env:
|
||||
Configuration: Release
|
||||
Solution_Path: SystemExtensions.slnx
|
||||
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.NetStandard.Tests.csproj
|
||||
DI_Test_Project_Path: SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj
|
||||
Solution_Path: SystemExtensions.sln
|
||||
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.Tests.csproj
|
||||
Source_Project_Path: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
|
||||
Core_Project_Path: SystemExtensions.NetCore\SystemExtensions.NetCore.csproj
|
||||
Actions_Allow_Unsecure_Commands: true
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '10.0.x'
|
||||
dotnet-version: '5.0.202'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.0.1
|
||||
@@ -43,35 +44,12 @@ jobs:
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
- name: Build SystemExtensions.NetStandard project
|
||||
- name: Build Slim project
|
||||
run: dotnet build SystemExtensions.NetStandard -c $env:Configuration
|
||||
|
||||
- name: Build SystemExtensions.NetCore project
|
||||
run: dotnet build SystemExtensions.NetCore -c $env:Configuration
|
||||
|
||||
- name: Build SystemExtensions.NetStandard.DependencyInjection project
|
||||
run: dotnet build SystemExtensions.NetStandard.DependencyInjection -c $env:Configuration
|
||||
|
||||
- name: Build SystemExtensions.NetStandard.Security project
|
||||
run: dotnet build SystemExtensions.NetStandard.Security -c $env:Configuration
|
||||
|
||||
- name: Build SystemExtensions.NetStandard.Generators project
|
||||
run: dotnet build SystemExtensions.NetStandard.Generators -c $env:Configuration
|
||||
|
||||
- name: Package SystemExtensions.NetStandard
|
||||
run: dotnet pack -c Release -o . SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
|
||||
|
||||
- name: Package SystemExtensions.NetCore
|
||||
run: dotnet pack -c Release -o . SystemExtensions.NetCore\SystemExtensions.NetCore.csproj
|
||||
|
||||
- name: Package SystemExtensions.NetStandard.DependencyInjection
|
||||
run: dotnet pack -c Release -o . SystemExtensions.NetStandard.DependencyInjection\SystemExtensions.NetStandard.DependencyInjection.csproj
|
||||
|
||||
- name: Package SystemExtensions.NetStandard.Security
|
||||
run: dotnet pack -c Release -o . SystemExtensions.NetStandard.Security\SystemExtensions.NetStandard.Security.csproj
|
||||
|
||||
- name: Package SystemExtensions.NetStandard.Generators
|
||||
run: dotnet pack -c Release -o . SystemExtensions.NetStandard.Generators\SystemExtensions.NetStandard.Generators.csproj
|
||||
|
||||
- name: Publish
|
||||
run: dotnet nuget push *.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
- name: Push nuget package
|
||||
uses: brandedoutcast/publish-nuget@v2.5.5
|
||||
with:
|
||||
PROJECT_FILE_PATH: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
|
||||
NUGET_KEY: ${{secrets.NUGET_API_KEY}}
|
||||
|
||||
@@ -19,23 +19,21 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
Solution_Path: SystemExtensions.slnx
|
||||
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.NetStandard.Tests.csproj
|
||||
DI_Test_Project_Path: SystemExtensions.DependencyInjection.Tests\SystemExtensions.NetStandard.DependencyInjection.Tests.csproj
|
||||
Sec_Test_Project_Path: SystemExtensions.NetStandard.Security.Tests\SystemExtensions.NetStandard.Security.Tests.csproj
|
||||
Solution_Path: Slim.sln
|
||||
Test_Project_Path: SystemExtensions.Tests\SystemExtensions.Tests.csproj
|
||||
Source_Project_Path: SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj
|
||||
Actions_Allow_Unsecure_Commands: true
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v3
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '10.0.x'
|
||||
dotnet-version: '5.0.202'
|
||||
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.0.1
|
||||
@@ -43,12 +41,6 @@ jobs:
|
||||
- name: Execute Unit Tests
|
||||
run: dotnet test $env:Test_Project_Path
|
||||
|
||||
- name: Execute DI Unit Tests
|
||||
run: dotnet test $env:DI_Test_Project_Path
|
||||
|
||||
- name: Execute Security Unit Tests
|
||||
run: dotnet test $env:Sec_Test_Project_Path
|
||||
|
||||
- name: Restore Project
|
||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
|
||||
env:
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using NSubstitute;
|
||||
using NSubstitute.ExceptionExtensions;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using SystemExtensions.NetStandard.DependencyInjection.Tests.Http.Models;
|
||||
|
||||
namespace SystemExtensions.NetStandard.DependencyInjection.Tests.Http;
|
||||
|
||||
[TestClass]
|
||||
public sealed class HttpClientBuilderTests
|
||||
{
|
||||
private const string SomeHeader = "SomeHeader";
|
||||
private const string SomeValue = "SomeValue";
|
||||
|
||||
private readonly HttpClientBuilder<object> httpClientBuilder;
|
||||
private readonly IServiceCollection serviceProducerMock = Substitute.For<IServiceCollection>();
|
||||
private readonly Uri baseAddress = new("http://contoso.co");
|
||||
|
||||
public HttpClientBuilderTests()
|
||||
{
|
||||
this.httpClientBuilder = new HttpClientBuilder<object>(this.serviceProducerMock);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Constructor_NullServiceProducer_Throws()
|
||||
{
|
||||
var action = () => new HttpClientBuilder<object>(null);
|
||||
|
||||
action.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WithMessageHandler_NullHandler_Throws()
|
||||
{
|
||||
var action = () => this.httpClientBuilder.WithMessageHandler(null);
|
||||
|
||||
action.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WithBaseAddress_NullBaseAddress_Throws()
|
||||
{
|
||||
var action = () => this.httpClientBuilder.WithBaseAddress(null);
|
||||
|
||||
action.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WithDefaultRequestHeadersSetup_NullSetup_Throws()
|
||||
{
|
||||
var action = () => this.httpClientBuilder.WithDefaultRequestHeadersSetup(null);
|
||||
|
||||
action.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Build_ReturnsServiceProducer()
|
||||
{
|
||||
var producer = this.httpClientBuilder.Build();
|
||||
|
||||
producer.Should().BeEquivalentTo(this.serviceProducerMock);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task HttpClientBuilder_RegistersClientCorrectly_IServiceProviderReturnsExpected()
|
||||
{
|
||||
var container = new ServiceCollection();
|
||||
var messageHandler = new HttpMessageHandlerMock();
|
||||
new HttpClientBuilder<object>(container)
|
||||
.WithBaseAddress(this.baseAddress)
|
||||
.WithDefaultRequestHeadersSetup(header => header.TryAddWithoutValidation(SomeHeader, SomeValue))
|
||||
.WithMaxResponseBufferSize(5)
|
||||
.WithMessageHandler(sp => messageHandler)
|
||||
.WithTimeout(TimeSpan.FromSeconds(5))
|
||||
.Build();
|
||||
|
||||
var di = container.BuildServiceProvider();
|
||||
var client = di.GetService<IHttpClient<object>>();
|
||||
await client.GetAsync("");
|
||||
|
||||
client.Should().NotBeNull();
|
||||
client.BaseAddress.Should().Be(this.baseAddress);
|
||||
client.DefaultRequestHeaders.Should().HaveCount(1);
|
||||
client.DefaultRequestHeaders.First().Key.Should().Be(SomeHeader);
|
||||
client.DefaultRequestHeaders.First().Value.Should().HaveCount(1);
|
||||
client.DefaultRequestHeaders.First().Value.First().Should().Be(SomeValue);
|
||||
client.MaxResponseContentBufferSize.Should().Be(5);
|
||||
client.Timeout.Should().Be(TimeSpan.FromSeconds(5));
|
||||
messageHandler.Called.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.NetStandard.DependencyInjection.Tests.Http.Models;
|
||||
public sealed class HttpMessageHandlerMock : HttpMessageHandler
|
||||
{
|
||||
public bool Called { get; private set; }
|
||||
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
this.Called = true;
|
||||
|
||||
return Task.FromResult(new HttpResponseMessage());
|
||||
}
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.5.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.5.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NSubstitute" Version="5.1.0" />
|
||||
<PackageReference Include="NSubstitute.Analyzers.CSharp" Version="1.0.17">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SystemExtensions.NetStandard.DependencyInjection\SystemExtensions.NetStandard.DependencyInjection.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,70 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using global::SystemExtensions.NetStandard.DependencyInjection.Tests.Http.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using NSubstitute;
|
||||
using System;
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.NetStandard.DependencyInjection.Tests.WebSockets;
|
||||
[TestClass]
|
||||
public sealed class HttpClientBuilderTests
|
||||
{
|
||||
private readonly ClientWebSocketBuilder<object> clientWebSocketBuilder;
|
||||
private readonly IServiceCollection serviceProducerMock = Substitute.For<IServiceCollection>();
|
||||
|
||||
public HttpClientBuilderTests()
|
||||
{
|
||||
this.clientWebSocketBuilder = new ClientWebSocketBuilder<object>(this.serviceProducerMock);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Constructor_NullServiceProducer_Throws()
|
||||
{
|
||||
var action = () => new ClientWebSocketBuilder<object>(null);
|
||||
|
||||
action.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WithInnerWebSocket_NullHandler_Throws()
|
||||
{
|
||||
var action = () => this.clientWebSocketBuilder.WithInnerWebSocket(null);
|
||||
|
||||
action.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WIthInnerWebSocketFactory_NullBaseAddress_Throws()
|
||||
{
|
||||
var action = () => this.clientWebSocketBuilder.WithInnerWebSocketFactory(null);
|
||||
|
||||
action.Should().Throw<ArgumentNullException>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Build_ReturnsServiceProducer()
|
||||
{
|
||||
var producer = this.clientWebSocketBuilder.Build();
|
||||
|
||||
producer.Should().BeEquivalentTo(this.serviceProducerMock);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task ClientWebSocketBuilder_RegistersClientCorrectly_IServiceProviderReturnsExpected()
|
||||
{
|
||||
var container = new ServiceCollection();
|
||||
var innerWebSocket = new ClientWebSocket();
|
||||
container.RegisterClientWebSocket<object>()
|
||||
.WithInnerWebSocket(innerWebSocket)
|
||||
.Build();
|
||||
|
||||
var di = container.BuildServiceProvider();
|
||||
var client = di.GetService<IClientWebSocket<object>>();
|
||||
client.Should().NotBeNull();
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Logging;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Extensions.Core;
|
||||
public static class LoggingExtensions
|
||||
{
|
||||
public static ScopedLogger<T> CreateScopedLogger<T>(this ILogger<T> logger, string flowIdentifier, [CallerMemberName] string? methodName = default)
|
||||
{
|
||||
return ScopedLogger<T>.Create(logger, methodName ?? string.Empty, flowIdentifier);
|
||||
}
|
||||
|
||||
public static ScopedLogger<T> CreateScopedLogger<T>(this ILogger<T> logger, [CallerMemberName] string? methodName = default)
|
||||
{
|
||||
return ScopedLogger<T>.Create(logger, methodName ?? string.Empty, string.Empty);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Core.Extensions;
|
||||
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
public static T ThrowIfNull<T>([NotNull] this T? obj, [CallerArgumentExpression("obj")] string? paramName = null)
|
||||
where T : class
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
throw new ArgumentNullException(paramName);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>System</RootNamespace>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<Version>1.9</Version>
|
||||
<Authors>Alexandru Macocian</Authors>
|
||||
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
|
||||
<Description>Extensions for the System namespace</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="../LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SystemExtensions.NetStandard\SystemExtensions.NetStandard.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Net.Http;
|
||||
using System.Net.WebSockets;
|
||||
|
||||
namespace System.Extensions;
|
||||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Register a scoped <see cref="IHttpClient{TScope}"/> to be used by the DI engine.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the scoped <see cref="IHttpClient{TScope}"/>.</typeparam>
|
||||
/// <param name="services"><see cref="IServiceCollection"/>.</param>
|
||||
/// <returns><see cref="HttpClientBuilder{T}"/> to build the http client.</returns>
|
||||
public static HttpClientBuilder<T> RegisterHttpClient<T>(this IServiceCollection services)
|
||||
{
|
||||
services.ThrowIfNull(nameof(services));
|
||||
|
||||
return new HttpClientBuilder<T>(services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a scoped <see cref="IClientWebSocket{TScope}"/> to be used by the DI engine.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the scoped <see cref="IClientWebSocket{TScope}"/>.</typeparam>
|
||||
/// <param name="services"><see cref="IServiceCollection"/>.</param>
|
||||
/// <returns><see cref="ClientWebSocketBuilder{T}"/> to build the websocket client.</returns>
|
||||
public static ClientWebSocketBuilder<T> RegisterClientWebSocket<T>(this IServiceCollection services)
|
||||
{
|
||||
services.ThrowIfNull(nameof(services));
|
||||
|
||||
return new ClientWebSocketBuilder<T>(services);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("SystemExtensions.NetStandard.DependencyInjection.Tests")]
|
||||
@@ -1,88 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Extensions;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace System.Net.Http;
|
||||
|
||||
public sealed class HttpClientBuilder<T>
|
||||
{
|
||||
private readonly IServiceCollection services;
|
||||
|
||||
private Uri? baseAddress;
|
||||
private Func<IServiceProvider, HttpMessageHandler>? httpMessageHandlerFactory;
|
||||
private Action<HttpRequestHeaders>? defaultRequestHeadersSetup;
|
||||
private bool disposeMessageHandler;
|
||||
private long maxResponseBufferSize = 2147483647L; //2GB default HttpClient value [https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.maxresponsecontentbuffersize?view=net-6.0]
|
||||
private TimeSpan timeout = TimeSpan.FromSeconds(100); //100 seconds default HttpClient value [https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.timeout?view=net-6.0]
|
||||
|
||||
internal HttpClientBuilder(IServiceCollection services)
|
||||
{
|
||||
services.ThrowIfNull(nameof(services));
|
||||
|
||||
this.services = services;
|
||||
}
|
||||
|
||||
public HttpClientBuilder<T> WithMessageHandler(Func<IServiceProvider, HttpMessageHandler> httpMessageHandlerFactory)
|
||||
{
|
||||
httpMessageHandlerFactory.ThrowIfNull(nameof(httpMessageHandlerFactory));
|
||||
|
||||
this.httpMessageHandlerFactory = httpMessageHandlerFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpClientBuilder<T> WithDisposeMessageHandler(bool disposeMessageHandler)
|
||||
{
|
||||
this.disposeMessageHandler = disposeMessageHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpClientBuilder<T> WithBaseAddress(Uri baseAddress)
|
||||
{
|
||||
baseAddress.ThrowIfNull(nameof(baseAddress));
|
||||
|
||||
this.baseAddress = baseAddress;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpClientBuilder<T> WithDefaultRequestHeadersSetup(Action<HttpRequestHeaders> setup)
|
||||
{
|
||||
setup.ThrowIfNull(nameof(setup));
|
||||
|
||||
this.defaultRequestHeadersSetup = setup;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpClientBuilder<T> WithMaxResponseBufferSize(long responseBufferSize)
|
||||
{
|
||||
this.maxResponseBufferSize = responseBufferSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpClientBuilder<T> WithTimeout(TimeSpan timeout)
|
||||
{
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IServiceCollection Build()
|
||||
{
|
||||
this.services.AddScoped<IHttpClient<T>>(sp =>
|
||||
{
|
||||
var client = this.httpMessageHandlerFactory is not null ?
|
||||
new HttpClient<T>(this.httpMessageHandlerFactory(sp), this.disposeMessageHandler) :
|
||||
new HttpClient<T>(true);
|
||||
|
||||
if (this.baseAddress is not null)
|
||||
{
|
||||
client.BaseAddress = this.baseAddress;
|
||||
}
|
||||
|
||||
this.defaultRequestHeadersSetup?.Invoke(client.DefaultRequestHeaders);
|
||||
client.MaxResponseContentBufferSize = this.maxResponseBufferSize;
|
||||
client.Timeout = this.timeout;
|
||||
return client;
|
||||
});
|
||||
|
||||
return this.services;
|
||||
}
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>System.DependencyInjection</RootNamespace>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Version>1.8</Version>
|
||||
<Authors>Alexandru Macocian</Authors>
|
||||
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
|
||||
<Description>Extensions for the Slim Dependency Injection engine</Description>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE" Link="LICENSE">
|
||||
<PackagePath></PackagePath>
|
||||
<Pack>True</Pack>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.1" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard" Version="1.8.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,58 +0,0 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Extensions;
|
||||
using System.Net.WebSockets;
|
||||
|
||||
namespace System.Net.Http;
|
||||
|
||||
public sealed class ClientWebSocketBuilder<T>
|
||||
{
|
||||
private readonly IServiceCollection services;
|
||||
|
||||
private ClientWebSocket? innerWebSocket;
|
||||
private Func<IServiceProvider, ClientWebSocket>? innerWebSocketFactory;
|
||||
|
||||
internal ClientWebSocketBuilder(IServiceCollection services)
|
||||
{
|
||||
services.ThrowIfNull(nameof(services));
|
||||
this.services = services;
|
||||
}
|
||||
|
||||
public ClientWebSocketBuilder<T> WithInnerWebSocket(ClientWebSocket innerWebSocket)
|
||||
{
|
||||
this.innerWebSocket = innerWebSocket.ThrowIfNull(nameof(innerWebSocket));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientWebSocketBuilder<T> WithInnerWebSocketFactory(Func<IServiceProvider, ClientWebSocket> innerWebSocketFactory)
|
||||
{
|
||||
this.innerWebSocketFactory = innerWebSocketFactory.ThrowIfNull(nameof(innerWebSocketFactory));
|
||||
return this;
|
||||
}
|
||||
|
||||
public IServiceCollection Build()
|
||||
{
|
||||
this.services.AddScoped<IClientWebSocket<T>>(sp =>
|
||||
{
|
||||
var logger = sp.GetService<ILogger<T>>();
|
||||
if (logger is null)
|
||||
{
|
||||
return new ClientWebSocket<T>();
|
||||
}
|
||||
|
||||
if (this.innerWebSocketFactory is not null)
|
||||
{
|
||||
return new ClientWebSocket<T>(this.innerWebSocketFactory(sp), logger);
|
||||
}
|
||||
|
||||
if (this.innerWebSocket is not null)
|
||||
{
|
||||
return new ClientWebSocket<T>(this.innerWebSocket, logger);
|
||||
}
|
||||
|
||||
return new ClientWebSocket<T>(logger);
|
||||
});
|
||||
|
||||
return this.services;
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Sybil;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
|
||||
namespace System.Extensions;
|
||||
#nullable enable
|
||||
[Generator(LanguageNames.CSharp)]
|
||||
public class BlittableStringGenerator : IIncrementalGenerator
|
||||
{
|
||||
private const string UsingSystem = "System";
|
||||
private const string UsingSystemRuntimeInterop = "System.Runtime.InteropServices";
|
||||
private const string AttributeNamespace = "System.Extensions";
|
||||
private const string AttributeName = "GenerateBlittableStringAttribute";
|
||||
private const string AttributeShortName = "GenerateBlittableString";
|
||||
private const string String = "String";
|
||||
private const string Public = "public";
|
||||
private const string Required = "required";
|
||||
private const string Size = "Size";
|
||||
private const string Int = "int";
|
||||
|
||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||
{
|
||||
context.RegisterPostInitializationOutput(context =>
|
||||
{
|
||||
var compilationUnitBuilder = SyntaxBuilder.CreateCompilationUnit()
|
||||
.WithNamespace(
|
||||
SyntaxBuilder.CreateNamespace(AttributeNamespace)
|
||||
.WithClass(SyntaxBuilder.CreateClass(AttributeName)
|
||||
.WithModifier(Public)
|
||||
.WithConstructor(SyntaxBuilder.CreateConstructor(AttributeName)
|
||||
.WithModifier(Public))
|
||||
.WithAttribute(SyntaxBuilder.CreateAttribute("AttributeUsage")
|
||||
.WithArgument(AttributeTargets.Assembly)
|
||||
.WithArgument("Inherited", false)
|
||||
.WithArgument("AllowMultiple", true))
|
||||
.WithProperty(SyntaxBuilder.CreateProperty(Int, Size)
|
||||
.WithModifier(Public)
|
||||
.WithModifier(Required)
|
||||
.WithAccessor(SyntaxBuilder.CreateGetter())
|
||||
.WithAccessor(SyntaxBuilder.CreateSetter()))
|
||||
.WithBaseClass(nameof(Attribute))));
|
||||
var compilationUnitSyntax = compilationUnitBuilder.Build();
|
||||
var source = compilationUnitSyntax.ToFullString();
|
||||
context.AddSource($"{AttributeName}.g", source);
|
||||
});
|
||||
|
||||
context.RegisterSourceOutput(context.CompilationProvider, (sourceProductionContext, compilation) =>
|
||||
{
|
||||
var assemblyAttributes =
|
||||
compilation.Assembly.GetAttributes().Where(a => a.AttributeClass != null &&
|
||||
(a.AttributeClass.Name == AttributeName || a.AttributeClass.Name == AttributeShortName));
|
||||
|
||||
foreach (var attr in assemblyAttributes)
|
||||
{
|
||||
// Extract the Size parameter from the named arguments.
|
||||
int? fixedSize = default;
|
||||
foreach (var arg in attr.NamedArguments)
|
||||
{
|
||||
if (arg.Key == Size && arg.Value.Value is int intValue)
|
||||
{
|
||||
fixedSize = intValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fixedSize is null)
|
||||
{
|
||||
// As Size is required, skip if not provided.
|
||||
continue;
|
||||
}
|
||||
|
||||
Execute(sourceProductionContext, (int)fixedSize);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void Execute(SourceProductionContext sourceProductionContext, int size)
|
||||
{
|
||||
var structName = $"{String}{size}";
|
||||
var builder = new StringBuilder();
|
||||
builder.AppendLine($"using {UsingSystem};");
|
||||
builder.AppendLine($"using {UsingSystemRuntimeInterop};");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine($"namespace {AttributeNamespace};");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("[StructLayout(LayoutKind.Sequential, Pack = 1)]");
|
||||
builder.AppendLine($"public unsafe partial struct {structName}");
|
||||
builder.AppendLine("{");
|
||||
builder.AppendLine($" public const int Size = {size};");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" public fixed char Value[Size];");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" public Span<char> AsSpan()");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine(" fixed (char* ptr = this.Value)");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine(" return MemoryMarshal.CreateSpan(ref *ptr, Size);");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" public readonly ReadOnlySpan<char> AsReadOnlySpan()");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine(" fixed (char* ptr = this.Value)");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine(" return new ReadOnlySpan<char>(ptr, Size);");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" public void Set(ReadOnlySpan<char> value)");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine(" fixed (char* ptr = this.Value)");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine(" var span = MemoryMarshal.CreateSpan(ref *ptr, Size);");
|
||||
builder.AppendLine(" span.Clear();");
|
||||
builder.AppendLine(" value[..Math.Min(value.Length, Size - 1)].CopyTo(span);");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" public override readonly string ToString()");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine(" var span = this.AsReadOnlySpan();");
|
||||
builder.AppendLine(" var nullIndex = span.IndexOf('\\0');");
|
||||
builder.AppendLine(" return nullIndex >= 0 ? new string(span[..nullIndex]) : new string(span);");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine($" public static implicit operator string({structName} value) => value.ToString();");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine($" public static implicit operator {structName}(string value)");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine($" var result = default({structName});");
|
||||
builder.AppendLine(" result.Set(value);");
|
||||
builder.AppendLine(" return result;");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine($" public static implicit operator ReadOnlySpan<char>({structName} value) => value.AsReadOnlySpan();");
|
||||
builder.AppendLine("}");
|
||||
|
||||
sourceProductionContext.AddSource($"{structName}.g.cs", builder.ToString());
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
@@ -1,78 +0,0 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
|
||||
namespace System.Extensions;
|
||||
|
||||
internal static class Diagnostics
|
||||
{
|
||||
public const string DependencyPropertyGenerator_NoAttributeFound = "DGD 0001";
|
||||
public const string DependencyPropertyGenerator_ClassMustBeTopLevel = "DGD 1001";
|
||||
public const string DependencyPropertyGenerator_ClassMustBePartial = "DGD 1002";
|
||||
public const string DependencyPropertyGenerator_ClassMustBeInNamespace = "DGD 1003";
|
||||
public const string DependencyPropertyGenerator_ClassMustImplementINotifyPropertyChanged = "DGD 1004";
|
||||
|
||||
public static Diagnostic MissingAttributeDiagnostic(string attributeName, string attributeNamespace) => Diagnostic.Create(
|
||||
new DiagnosticDescriptor(
|
||||
DependencyPropertyGenerator_NoAttributeFound,
|
||||
$"{attributeNamespace}.{attributeName} not found",
|
||||
"Could not find attribute with name {0} in namespace {1}.",
|
||||
"SystemExtensions.NetStandard.Generators",
|
||||
DiagnosticSeverity.Error,
|
||||
true,
|
||||
$"This error occurs when the attribute generated by the {nameof(NotifyPropertyChangedGenerator)} is not found",
|
||||
null),
|
||||
Location.None,
|
||||
attributeName, attributeNamespace);
|
||||
|
||||
public static Diagnostic ClassNotTopLevelDiagnostic(string className, string containingSymbol, SyntaxTree syntaxTree, TextSpan textSpan) => Diagnostic.Create(
|
||||
new DiagnosticDescriptor(
|
||||
DependencyPropertyGenerator_ClassMustBeTopLevel,
|
||||
$"{className} must be top level",
|
||||
"Class {0} must be top level. It is currently declared under {1}.",
|
||||
"SystemExtensions.NetStandard.Generators",
|
||||
DiagnosticSeverity.Error,
|
||||
true,
|
||||
null,
|
||||
null),
|
||||
Location.Create(syntaxTree, textSpan),
|
||||
className, containingSymbol);
|
||||
|
||||
public static Diagnostic ClassNotPartial(string className) => Diagnostic.Create(
|
||||
new DiagnosticDescriptor(
|
||||
DependencyPropertyGenerator_ClassMustBePartial,
|
||||
$"{className} is not partial",
|
||||
"Class {0} must be marked as partial in order for the generator to work",
|
||||
"SystemExtensions.NetStandard.Generators",
|
||||
DiagnosticSeverity.Error,
|
||||
true,
|
||||
null,
|
||||
null),
|
||||
Location.None,
|
||||
className);
|
||||
|
||||
public static Diagnostic ClassNotInNamespace(string className) => Diagnostic.Create(
|
||||
new DiagnosticDescriptor(
|
||||
DependencyPropertyGenerator_ClassMustBeInNamespace,
|
||||
$"{className} is not defined in a namespace",
|
||||
"Class {0} must be defined inside a namespace for the generator to work",
|
||||
"SystemExtensions.NetStandard.Generators",
|
||||
DiagnosticSeverity.Error,
|
||||
true,
|
||||
null,
|
||||
null),
|
||||
Location.None,
|
||||
className);
|
||||
|
||||
public static Diagnostic ClassDoesNotImplementINotifyPropertyChanged(string className) => Diagnostic.Create(
|
||||
new DiagnosticDescriptor(
|
||||
DependencyPropertyGenerator_ClassMustImplementINotifyPropertyChanged,
|
||||
$"{className} must implement INotifyPropertyChanged",
|
||||
"Class {0} must implement INotifyPropertyChanged for the generator to work",
|
||||
"SystemExtensions.NetStandard.Generators",
|
||||
DiagnosticSeverity.Error,
|
||||
true,
|
||||
null,
|
||||
null),
|
||||
Location.None,
|
||||
className);
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Sybil;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
|
||||
namespace System.Extensions;
|
||||
#nullable enable
|
||||
[Generator(LanguageNames.CSharp)]
|
||||
public class FixedArrayGenerator : IIncrementalGenerator
|
||||
{
|
||||
private const string UsingSystem = "System";
|
||||
private const string UsingSystemRuntimeInterop = "System.Runtime.InteropServices";
|
||||
private const string AttributeNamespace = "System.Extensions";
|
||||
private const string AttributeName = "GenerateFixedArrayAttribute";
|
||||
private const string AttributeShortName = "GenerateFixedArray";
|
||||
private const string Array = "Array";
|
||||
private const string Public = "public";
|
||||
private const string Struct = "struct";
|
||||
private const string Required = "required";
|
||||
private const string Size = "Size";
|
||||
private const string Int = "int";
|
||||
private const string TType = "T";
|
||||
|
||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||
{
|
||||
context.RegisterPostInitializationOutput(context =>
|
||||
{
|
||||
var compilationUnitBuilder = SyntaxBuilder.CreateCompilationUnit()
|
||||
.WithNamespace(
|
||||
SyntaxBuilder.CreateNamespace(AttributeNamespace)
|
||||
.WithClass(SyntaxBuilder.CreateClass(AttributeName)
|
||||
.WithModifier(Public)
|
||||
.WithTypeParameter(SyntaxBuilder.CreateTypeParameter(TType))
|
||||
.WithTypeParameterConstraint(SyntaxBuilder.CreateTypeParameterConstraint(TType)
|
||||
.WithType(Struct))
|
||||
.WithConstructor(SyntaxBuilder.CreateConstructor(AttributeName)
|
||||
.WithModifier(Public))
|
||||
.WithAttribute(SyntaxBuilder.CreateAttribute("AttributeUsage")
|
||||
.WithArgument(AttributeTargets.Assembly)
|
||||
.WithArgument("Inherited", false)
|
||||
.WithArgument("AllowMultiple", true))
|
||||
.WithProperty(SyntaxBuilder.CreateProperty(Int, Size)
|
||||
.WithModifier(Public)
|
||||
.WithModifier(Required)
|
||||
.WithAccessor(SyntaxBuilder.CreateGetter())
|
||||
.WithAccessor(SyntaxBuilder.CreateSetter()))
|
||||
.WithBaseClass(nameof(Attribute))));
|
||||
var compilationUnitSyntax = compilationUnitBuilder.Build();
|
||||
var source = compilationUnitSyntax.ToFullString();
|
||||
context.AddSource($"{AttributeName}.g", source);
|
||||
});
|
||||
|
||||
context.RegisterSourceOutput(context.CompilationProvider, (sourceProductionContext, compilation) =>
|
||||
{
|
||||
var assemblyAttributes =
|
||||
compilation.Assembly.GetAttributes().Where(a => a.AttributeClass != null &&
|
||||
(a.AttributeClass.Name == AttributeName || a.AttributeClass.Name == AttributeShortName));
|
||||
|
||||
foreach (var attr in assemblyAttributes)
|
||||
{
|
||||
// Extract the type argument (T) from GenerateFixedArrayAttribute<T>
|
||||
var namedTypeSymbol = attr.AttributeClass as INamedTypeSymbol;
|
||||
if (namedTypeSymbol is null || namedTypeSymbol.TypeArguments.Length != 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var targetType = namedTypeSymbol.TypeArguments[0].ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);
|
||||
// Extract the Size parameter from the named arguments.
|
||||
int? fixedSize = default;
|
||||
foreach (var arg in attr.NamedArguments)
|
||||
{
|
||||
if (arg.Key == Size && arg.Value.Value is int intValue)
|
||||
{
|
||||
fixedSize = intValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fixedSize is null)
|
||||
{
|
||||
// As Size is required, skip if not provided.
|
||||
continue;
|
||||
}
|
||||
|
||||
Execute(sourceProductionContext, targetType, (int)fixedSize);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void Execute(SourceProductionContext sourceProductionContext, string targetType, int size)
|
||||
{
|
||||
var capitalizedType = targetType.ToUpperInvariant()[0] + targetType.Substring(1);
|
||||
var structName = $"{Array}{size}{capitalizedType}";
|
||||
var builder = new StringBuilder();
|
||||
builder.AppendLine($"using {UsingSystem};");
|
||||
builder.AppendLine($"using {UsingSystemRuntimeInterop};");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine($"namespace {AttributeNamespace};");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("[StructLayout(LayoutKind.Sequential, Pack = 1)]");
|
||||
builder.AppendLine($"public unsafe struct {structName}");
|
||||
builder.AppendLine("{");
|
||||
builder.AppendLine($" private const int Size = {size};");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine($" private fixed {targetType} elements[Size];");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine(" public int Length => Size;");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine($" public ref {targetType} this[int index]");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine(" get");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine(" if ((uint)index >= Size) throw new IndexOutOfRangeException();");
|
||||
builder.AppendLine($" return ref this.elements[index];");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine($" public Span<{targetType}> AsSpan()");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine($" fixed ({targetType}* ptr = this.elements)");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine($" return MemoryMarshal.CreateSpan(ref *ptr, Size);");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine($" public readonly ReadOnlySpan<{targetType}> AsReadOnlySpan()");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine($" fixed ({targetType}* ptr = this.elements)");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine($" return new ReadOnlySpan<{targetType}>(ptr, Size);");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine($" public void Set(ReadOnlySpan<{targetType}> value)");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine($" fixed ({targetType}* ptr = this.elements)");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine($" var span = MemoryMarshal.CreateSpan(ref *ptr, Size);");
|
||||
builder.AppendLine(" span.Clear();");
|
||||
builder.AppendLine(" value[..Math.Min(value.Length, Size)].CopyTo(span);");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine($" public void Clear()");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine($" fixed ({targetType}* ptr = this.elements)");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine($" MemoryMarshal.CreateSpan(ref *ptr, Size).Clear();");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine();
|
||||
builder.AppendLine($" public static {structName} From{capitalizedType}Array({targetType}[] array)");
|
||||
builder.AppendLine(" {");
|
||||
builder.AppendLine($" var arr = default({structName});");
|
||||
builder.AppendLine(" arr.Set(array);");
|
||||
builder.AppendLine(" return arr;");
|
||||
builder.AppendLine(" }");
|
||||
builder.AppendLine("}");
|
||||
|
||||
sourceProductionContext.AddSource($"{structName}.g.cs", builder.ToString());
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
@@ -1,173 +0,0 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Sybil;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace System.Extensions;
|
||||
#nullable enable
|
||||
[Generator(LanguageNames.CSharp)]
|
||||
public class NotifyPropertyChangedGenerator : IIncrementalGenerator
|
||||
{
|
||||
private const string AttributeNamespace = "System.Extensions";
|
||||
private const string AttributeName = "GenerateNotifyPropertyChangedAttribute";
|
||||
private const string AttributeShortName = "GenerateNotifyPropertyChanged";
|
||||
private const string PropertyChangedEventHandler = "PropertyChangedEventHandler";
|
||||
private const string NullablePropertyChangedEventHandler = "PropertyChangedEventHandler?";
|
||||
private const string PropertyChanged = "PropertyChanged";
|
||||
private const string Partial = "partial";
|
||||
private const string Public = "public";
|
||||
|
||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||
{
|
||||
context.RegisterPostInitializationOutput(context =>
|
||||
{
|
||||
var compilationUnitBuilder = SyntaxBuilder.CreateCompilationUnit()
|
||||
.WithNamespace(
|
||||
SyntaxBuilder.CreateNamespace(AttributeNamespace)
|
||||
.WithClass(SyntaxBuilder.CreateClass(AttributeName)
|
||||
.WithModifier(Public)
|
||||
.WithConstructor(SyntaxBuilder.CreateConstructor(AttributeName)
|
||||
.WithModifier(Public))
|
||||
.WithAttribute(SyntaxBuilder.CreateAttribute("AttributeUsage")
|
||||
.WithArgument(AttributeTargets.Field)
|
||||
.WithArgument("Inherited", false)
|
||||
.WithArgument("AllowMultiple", false))
|
||||
.WithBaseClass(nameof(Attribute))));
|
||||
var compilationUnitSyntax = compilationUnitBuilder.Build();
|
||||
var source = compilationUnitSyntax.ToFullString();
|
||||
context.AddSource($"{AttributeName}.g", source);
|
||||
});
|
||||
|
||||
var classDeclarations = context.SyntaxProvider.CreateSyntaxProvider(
|
||||
predicate: static (s, _) => s is FieldDeclarationSyntax,
|
||||
transform: static (ctx, _) => GetFilteredFieldDeclarationSyntax(ctx)).Where(static c => c is not null);
|
||||
|
||||
var compilationAndClasses = context.CompilationProvider.Combine(classDeclarations.Collect());
|
||||
context.RegisterSourceOutput(compilationAndClasses, (sourceProductionContext, tuple) => Execute(tuple.Left, tuple.Right, sourceProductionContext));
|
||||
}
|
||||
|
||||
private static ClassDeclarationSyntax? GetFilteredFieldDeclarationSyntax(GeneratorSyntaxContext context)
|
||||
{
|
||||
var fieldDeclarationSyntax = (FieldDeclarationSyntax)context.Node;
|
||||
if (fieldDeclarationSyntax.AttributeLists
|
||||
.SelectMany(l => l.Attributes)
|
||||
.OfType<AttributeSyntax>()
|
||||
.Any(s => s.Name.ToString() == AttributeName || s.Name.ToString() == AttributeShortName))
|
||||
{
|
||||
return fieldDeclarationSyntax.Parent as ClassDeclarationSyntax;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
private static void Execute(Compilation compilation, ImmutableArray<ClassDeclarationSyntax?> classes, SourceProductionContext sourceProductionContext)
|
||||
{
|
||||
if (classes.IsDefaultOrEmpty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var maybeLanguageVersion = (compilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions)?.LanguageVersion;
|
||||
if (!maybeLanguageVersion.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var languageVersion = maybeLanguageVersion.Value;
|
||||
var distinctClasses = classes.Distinct();
|
||||
foreach (var c in distinctClasses.OfType<ClassDeclarationSyntax>())
|
||||
{
|
||||
var className = c.Identifier.ToFullString();
|
||||
if (!c.Modifiers.Any(m => m.ToString() == Partial))
|
||||
{
|
||||
Diagnostics.ClassNotPartial(className);
|
||||
continue;
|
||||
}
|
||||
|
||||
var originalNamespaceSyntax = GetParentOfType<BaseNamespaceDeclarationSyntax>(c);
|
||||
if (originalNamespaceSyntax is null)
|
||||
{
|
||||
Diagnostics.ClassNotInNamespace(className);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!c.Members
|
||||
.OfType<EventFieldDeclarationSyntax>()
|
||||
.Any(eventField =>
|
||||
(eventField.Declaration.Variables.Any(variable => variable.Identifier.Text == PropertyChanged) &&
|
||||
eventField.Modifiers.Any(modifier => modifier.Text == Public) &&
|
||||
eventField.Declaration.Type.ToString() == PropertyChangedEventHandler) ||
|
||||
eventField.Declaration.Type.ToString() == NullablePropertyChangedEventHandler))
|
||||
{
|
||||
Diagnostics.ClassDoesNotImplementINotifyPropertyChanged(className);
|
||||
continue;
|
||||
}
|
||||
|
||||
var generatedClassBuilder = SyntaxBuilder.CreateClass(className)
|
||||
.WithModifiers(string.Join(" ", c.Modifiers.Select(m => m.ToFullString())));
|
||||
var compilationUnitBuilder = SyntaxBuilder.CreateCompilationUnit()
|
||||
.WithNamespace(
|
||||
(languageVersion >= LanguageVersion.CSharp10 ?
|
||||
SyntaxBuilder.CreateFileScopedNamespace(originalNamespaceSyntax.Name.ToFullString()) :
|
||||
SyntaxBuilder.CreateNamespace(originalNamespaceSyntax.Name.ToFullString()))
|
||||
.WithClass(generatedClassBuilder));
|
||||
|
||||
foreach (var field in c.DescendantNodes().OfType<FieldDeclarationSyntax>())
|
||||
{
|
||||
if (field.AttributeLists
|
||||
.SelectMany(l => l.Attributes)
|
||||
.OfType<AttributeSyntax>()
|
||||
.Any(s => s.Name.ToString() == AttributeName ||
|
||||
s.Name.ToString() == AttributeShortName) is false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var fieldName = field.Declaration.Variables.First().Identifier.ToFullString();
|
||||
var propertyName = fieldName.TrimStart('_');
|
||||
propertyName = $"{char.ToUpper(propertyName[0])}{propertyName.Substring(1)}";
|
||||
var propertyBuilder = SyntaxBuilder.CreateProperty(field.Declaration.Type.ToFullString(), propertyName)
|
||||
.WithModifier(Public)
|
||||
.WithAccessor(SyntaxBuilder.CreateGetter()
|
||||
.WithBody($"return this.{fieldName};"))
|
||||
.WithAccessor(SyntaxBuilder.CreateSetter()
|
||||
.WithBody($"this.{fieldName} = value;\r\nthis.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof({propertyName})));"));
|
||||
generatedClassBuilder.WithProperty(propertyBuilder);
|
||||
}
|
||||
|
||||
var generatedSyntax = compilationUnitBuilder.Build();
|
||||
if (originalNamespaceSyntax.Usings.Count != 0)
|
||||
{
|
||||
generatedSyntax = generatedSyntax.AddUsings([.. originalNamespaceSyntax.Usings]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (originalNamespaceSyntax.Parent is CompilationUnitSyntax compilationUnit)
|
||||
{
|
||||
generatedSyntax = generatedSyntax.AddUsings([.. compilationUnit.Usings]);
|
||||
}
|
||||
}
|
||||
|
||||
var fileSource = $"#nullable enable\n{generatedSyntax.ToFullString()}\n#nullable disable";
|
||||
sourceProductionContext.AddSource($"{className}.g", fileSource);
|
||||
}
|
||||
}
|
||||
|
||||
private static T? GetParentOfType<T>(SyntaxNode syntaxNode)
|
||||
{
|
||||
if (syntaxNode.Parent is null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
if (syntaxNode.Parent is T parentNode)
|
||||
{
|
||||
return parentNode;
|
||||
}
|
||||
|
||||
return GetParentOfType<T>(syntaxNode.Parent);
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Authors>Alexandru Macocian</Authors>
|
||||
<Description>Source generators extensions for netstandard2.0.</Description>
|
||||
<Version>0.1.7</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||
<IsRoslynComponent>true</IsRoslynComponent>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Sybil" Version="0.8.4" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Package the generator in the analyzer directory of the nuget package -->
|
||||
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||
<None Include="$(OutputPath)\Sybil.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,104 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Encryption;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.NetStandard.Security.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class AesEncrypterTests
|
||||
{
|
||||
private ISymmetricEncrypter symmetricEncrypter;
|
||||
private string keyString;
|
||||
private byte[] keyBytes;
|
||||
private byte[] ivBytes;
|
||||
private string ivString;
|
||||
private string toEncryptString;
|
||||
private byte[] toEncryptBytes;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
this.symmetricEncrypter = new AesEncrypter();
|
||||
this.keyBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2 };
|
||||
this.keyString = Convert.ToBase64String(this.keyBytes);
|
||||
this.ivBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6 };
|
||||
this.ivString = Convert.ToBase64String(this.ivBytes);
|
||||
this.toEncryptBytes = Encoding.UTF8.GetBytes("toEncrypt");
|
||||
this.toEncryptString = Convert.ToBase64String(this.toEncryptBytes);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task EncryptDecryptStringWithStringKeyStringIv()
|
||||
{
|
||||
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, this.toEncryptString).ConfigureAwait(false);
|
||||
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false);
|
||||
|
||||
this.toEncryptString.Should().Be(decrypted);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task EncryptDecryptStringWithByteKeyByteIv()
|
||||
{
|
||||
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, this.toEncryptString).ConfigureAwait(false);
|
||||
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false);
|
||||
|
||||
this.toEncryptString.Should().Be(decrypted);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task EncryptDecryptByteWithStringKeyStringIv()
|
||||
{
|
||||
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, this.toEncryptBytes).ConfigureAwait(false);
|
||||
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false);
|
||||
|
||||
this.toEncryptBytes.Should().BeEquivalentTo(decrypted);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task EncryptDecryptByteWithByteKeyByteIv()
|
||||
{
|
||||
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, this.toEncryptBytes).ConfigureAwait(false);
|
||||
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false);
|
||||
|
||||
this.toEncryptBytes.Should().BeEquivalentTo(decrypted);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task EncryptDecryptStreamWithStringKeyStringIv()
|
||||
{
|
||||
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyString, this.ivString, new MemoryStream(this.toEncryptBytes)).ConfigureAwait(false);
|
||||
encrypted.Position = 0;
|
||||
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyString, this.ivString, encrypted).ConfigureAwait(false);
|
||||
|
||||
this.toEncryptBytes.Should().BeEquivalentTo(((MemoryStream)decrypted).ToArray());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task EncryptDecryptStreamWithByteKeyByteIv()
|
||||
{
|
||||
var encrypted = await this.symmetricEncrypter.Encrypt(this.keyBytes, this.ivBytes, new MemoryStream(this.toEncryptBytes)).ConfigureAwait(false);
|
||||
encrypted.Position = 0;
|
||||
var decrypted = await this.symmetricEncrypter.Decrypt(this.keyBytes, this.ivBytes, encrypted).ConfigureAwait(false);
|
||||
|
||||
this.toEncryptBytes.Should().BeEquivalentTo(((MemoryStream)decrypted).ToArray());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetEncryptionStreamReturnsCryptoStream()
|
||||
{
|
||||
var encryptionStream = this.symmetricEncrypter.GetEncryptionStream(this.keyBytes, this.ivBytes, new MemoryStream());
|
||||
encryptionStream.Should().BeAssignableTo<CryptoStream>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetDecryptionStreamReturnsCryptoStream()
|
||||
{
|
||||
var encryptionStream = this.symmetricEncrypter.GetDecryptionStream(this.keyBytes, this.ivBytes, new MemoryStream());
|
||||
encryptionStream.Should().BeAssignableTo<CryptoStream>();
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Linq;
|
||||
using System.Security.Rng;
|
||||
|
||||
namespace SystemExtensions.NetStandard.Security.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class CryptoRngProviderTests
|
||||
{
|
||||
private CryptoRngProvider cryptoRngProvider;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
this.cryptoRngProvider = new CryptoRngProvider();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetBytes_ShouldSetValues()
|
||||
{
|
||||
var bytes = new byte[100];
|
||||
|
||||
this.cryptoRngProvider.GetBytes(bytes);
|
||||
|
||||
bytes.All(b => b == 0).Should().BeFalse();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetNonZeroBytes_ShouldSetNonZeroValues()
|
||||
{
|
||||
var bytes = new byte[100];
|
||||
|
||||
this.cryptoRngProvider.GetNonZeroBytes(bytes);
|
||||
|
||||
bytes.All(b => b != 0).Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetBytes_ShouldReturnBytes()
|
||||
{
|
||||
var bytes = this.cryptoRngProvider.GetBytes(10);
|
||||
|
||||
bytes.Length.Should().Be(10);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetNonZeroBytes_ShouldReturnBytes()
|
||||
{
|
||||
var bytes = this.cryptoRngProvider.GetNonZeroBytes(10);
|
||||
|
||||
bytes.Length.Should().Be(10);
|
||||
}
|
||||
}
|
||||
-260
@@ -1,260 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Security.Hashing;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.NetStandard.Security.Tests;
|
||||
|
||||
[TestClass]
|
||||
public sealed class Rfc2898DeriveBytesPasswordHashingServiceTests
|
||||
{
|
||||
private const int TooShortHashLength = 31;
|
||||
private const int DesiredHashLength = 32;
|
||||
private const int Iterations = 10000;
|
||||
private const int TooLittleIterations = 1000;
|
||||
|
||||
private readonly Rfc2898DeriveBytesPasswordHashingService rfc2898DeriveBytesPasswordHashingService = new();
|
||||
|
||||
private byte[] tooShortSaltBytes;
|
||||
private string tooShortSaltString;
|
||||
private byte[] incorrectSaltBytes;
|
||||
private string incorrectSaltString;
|
||||
private byte[] saltBytes;
|
||||
private string saltString;
|
||||
private byte[] passwordBytes;
|
||||
private string passwordString;
|
||||
private byte[] incorrectPasswordBytes;
|
||||
private string incorrectPasswordString;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
this.tooShortSaltBytes = new byte[16];
|
||||
this.tooShortSaltString = Convert.ToBase64String(this.tooShortSaltBytes);
|
||||
this.saltBytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
|
||||
this.incorrectSaltBytes = new byte[32];
|
||||
this.incorrectSaltString = Convert.ToBase64String(this.incorrectSaltBytes);
|
||||
this.saltString = Convert.ToBase64String(this.saltBytes);
|
||||
this.passwordBytes = new byte[] { 5, 1, 2, 34, 35, 123, 4, 23, 1, 235, 32, 234 };
|
||||
this.passwordString = Convert.ToBase64String(this.passwordBytes);
|
||||
this.incorrectPasswordBytes = new byte[] { 14, 123, 23, 4, 2, 1, 23, 25 };
|
||||
this.incorrectPasswordString = Convert.ToBase64String(this.incorrectPasswordBytes);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void PasswordNull_HashBytes_Throws_ArgumentNullException()
|
||||
{
|
||||
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(null, this.saltBytes, DesiredHashLength, Iterations));
|
||||
|
||||
action.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void PasswordNull_HashString_Throws_ArgumentNullException()
|
||||
{
|
||||
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(null, this.saltString, DesiredHashLength, Iterations));
|
||||
|
||||
action.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void SaltNull_HashBytes_Throws_ArgumentNullException()
|
||||
{
|
||||
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, null, DesiredHashLength, Iterations));
|
||||
|
||||
action.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void SaltNull_HashString_Throws_ArgumentNullException()
|
||||
{
|
||||
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, null, DesiredHashLength, Iterations));
|
||||
|
||||
action.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void HashLengthTooSmall_HashBytes_Throws_InvalidOperationException()
|
||||
{
|
||||
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, TooShortHashLength, Iterations));
|
||||
|
||||
action.Should().ThrowAsync<InvalidOperationException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void HashLengthTooSmall_HashString_Throws_InvalidOperationException()
|
||||
{
|
||||
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, TooShortHashLength, Iterations));
|
||||
|
||||
action.Should().ThrowAsync<InvalidOperationException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void TooLittleIterations_HashBytes_Throws_InvalidOperationException()
|
||||
{
|
||||
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, TooLittleIterations));
|
||||
|
||||
action.Should().ThrowAsync<InvalidOperationException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void TooLittleIterations_HashString_Throws_InvalidOperationException()
|
||||
{
|
||||
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, TooLittleIterations));
|
||||
|
||||
action.Should().ThrowAsync<InvalidOperationException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void TooShortSalt_HashBytes_Throws_InvalidOperationException()
|
||||
{
|
||||
var action = new Func<Task<byte[]>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.tooShortSaltBytes, DesiredHashLength, TooLittleIterations));
|
||||
|
||||
action.Should().ThrowAsync<InvalidOperationException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void TooShortSalt_HashString_Throws_InvalidOperationException()
|
||||
{
|
||||
var action = new Func<Task<string>>(() => this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.tooShortSaltString, DesiredHashLength, TooLittleIterations));
|
||||
|
||||
action.Should().ThrowAsync<InvalidOperationException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void PasswordNull_VerifyBytes_Throws_ArgumentNullException()
|
||||
{
|
||||
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(null, this.incorrectPasswordBytes, this.saltBytes, Iterations));
|
||||
|
||||
action.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void PasswordNull_VerifyString_Throws_ArgumentNullException()
|
||||
{
|
||||
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(null, this.incorrectPasswordString, this.saltString, Iterations));
|
||||
|
||||
action.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void HashNull_VerifyBytes_Throws_ArgumentNullException()
|
||||
{
|
||||
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, null, this.saltBytes, Iterations));
|
||||
|
||||
action.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void HashNull_VerifyString_Throws_ArgumentNullException()
|
||||
{
|
||||
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, null, this.saltString, Iterations));
|
||||
|
||||
action.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void SaltNull_VerifyBytes_Throws_ArgumentNullException()
|
||||
{
|
||||
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, this.incorrectPasswordBytes, null, Iterations));
|
||||
|
||||
action.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void SaltNull_VerifyString_Throws_ArgumentNullException()
|
||||
{
|
||||
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, this.incorrectPasswordString, null, Iterations));
|
||||
|
||||
action.Should().ThrowAsync<ArgumentNullException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void TooLittleIterations_VerifyBytes_Throws_InvalidOperationException()
|
||||
{
|
||||
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordBytes, this.incorrectPasswordBytes, this.saltBytes, TooLittleIterations));
|
||||
|
||||
action.Should().ThrowAsync<InvalidOperationException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public void TooLittleIterations_VerifyString_Throws_InvalidOperationException()
|
||||
{
|
||||
var action = new Func<Task<bool>>(() => this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(this.passwordString, this.incorrectPasswordString, this.saltString, TooLittleIterations));
|
||||
|
||||
action.Should().ThrowAsync<InvalidOperationException>();
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task HashBytes_ReturnsHashedBytes()
|
||||
{
|
||||
var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations);
|
||||
|
||||
hashedBytes.Should().NotBeNull();
|
||||
hashedBytes.Should().HaveCount(DesiredHashLength);
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task HashString_ReturnsHashedString()
|
||||
{
|
||||
var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations);
|
||||
|
||||
hashedString.Should().NotBeNull();
|
||||
var hashedBytes = Convert.FromBase64String(hashedString);
|
||||
hashedBytes.Should().HaveCount(DesiredHashLength);
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task VerifyBytes_CorrectPassword_ReturnsTrue()
|
||||
{
|
||||
var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations);
|
||||
|
||||
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.passwordBytes, this.saltBytes, Iterations);
|
||||
|
||||
result.Should().BeTrue();
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task VerifyString_CorrectPassword_ReturnsTrue()
|
||||
{
|
||||
var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations);
|
||||
|
||||
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.passwordString, this.saltString, Iterations);
|
||||
|
||||
result.Should().BeTrue();
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task VerifyBytes_IncorrectPassword_ReturnsFalse()
|
||||
{
|
||||
var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations);
|
||||
|
||||
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.incorrectPasswordBytes, this.saltBytes, Iterations);
|
||||
|
||||
result.Should().BeFalse();
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task VerifyString_IncorrectPassword_ReturnsFalse()
|
||||
{
|
||||
var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations);
|
||||
|
||||
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.incorrectPasswordString, this.saltString, Iterations);
|
||||
|
||||
result.Should().BeFalse();
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task VerifyBytes_IncorrectSalt_ReturnsFalse()
|
||||
{
|
||||
var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations);
|
||||
|
||||
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.passwordBytes, this.incorrectSaltBytes, Iterations);
|
||||
|
||||
result.Should().BeFalse();
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task VerifyString_IncorrectSalt_ReturnsFalse()
|
||||
{
|
||||
var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations);
|
||||
|
||||
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.passwordString, this.incorrectSaltString, Iterations);
|
||||
|
||||
result.Should().BeFalse();
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task VerifyBytes_IncorrectIterations_ReturnsFalse()
|
||||
{
|
||||
var hashedBytes = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordBytes, this.saltBytes, DesiredHashLength, Iterations);
|
||||
|
||||
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedBytes, this.passwordBytes, this.saltBytes, Iterations + 1);
|
||||
|
||||
result.Should().BeFalse();
|
||||
}
|
||||
[TestMethod]
|
||||
public async Task VerifyString_IncorrectIterations_ReturnsFalse()
|
||||
{
|
||||
var hashedString = await this.rfc2898DeriveBytesPasswordHashingService.Hash(this.passwordString, this.saltString, DesiredHashLength, Iterations);
|
||||
|
||||
var result = await this.rfc2898DeriveBytesPasswordHashingService.VerifyPassword(hashedString, this.passwordString, this.saltString, Iterations + 1);
|
||||
|
||||
result.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Security.Encryption;
|
||||
|
||||
namespace SystemExtensions.NetStandard.Security.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class SecureStringTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void SecureString_NewSecureString_ReturnsValue()
|
||||
{
|
||||
var str = new SecureString("hello");
|
||||
|
||||
str.Value.Should().Be("hello");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SecureStringEmpty_AreEqual()
|
||||
{
|
||||
var str = SecureString.Empty;
|
||||
str.Should().Be(SecureString.Empty);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SecureStringEmpty_Equals_StringEmpty()
|
||||
{
|
||||
var ss = SecureString.Empty;
|
||||
var s = string.Empty;
|
||||
|
||||
ss.Should().Be(s);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SecureString_Equals_OtherSecureString()
|
||||
{
|
||||
var ss1 = new SecureString("Hello");
|
||||
var ss2 = new SecureString("Hello");
|
||||
|
||||
ss1.Equals(ss2).Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[DataRow("hello", "hello", true)]
|
||||
[DataRow("hello", "henlo", false)]
|
||||
public void SecureString_EqualOperator_OtherSecureString(string str1, string str2, bool isEqual)
|
||||
{
|
||||
var ss1 = new SecureString(str1);
|
||||
var ss2 = new SecureString(str2);
|
||||
|
||||
(ss1 == ss2).Should().Be(isEqual);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[DataRow("hello", "hello", false)]
|
||||
[DataRow("hello", "henlo", true)]
|
||||
public void SecureString_DifferentOperator_OtherSecureString(string str1, string str2, bool isDifferent)
|
||||
{
|
||||
var ss1 = new SecureString(str1);
|
||||
var ss2 = new SecureString(str2);
|
||||
|
||||
(ss1 != ss2).Should().Be(isDifferent);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[DataRow("hello", "hello", true)]
|
||||
[DataRow("hello", "henlo", false)]
|
||||
public void SecureString_EqualOperator_String(string str1, string str2, bool isEqual)
|
||||
{
|
||||
var ss1 = new SecureString(str1);
|
||||
|
||||
(ss1 == str2).Should().Be(isEqual);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[DataRow("hello", "hello", false)]
|
||||
[DataRow("hello", "henlo", true)]
|
||||
public void SecureString_DifferentOperator_String(string str1, string str2, bool isDifferent)
|
||||
{
|
||||
var ss1 = new SecureString(str1);
|
||||
|
||||
(ss1 != str2).Should().Be(isDifferent);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SecureString_PlusOperator_SecureString()
|
||||
{
|
||||
var ss1 = new SecureString("Hello ");
|
||||
var ss2 = new SecureString("World");
|
||||
|
||||
(ss1 + ss2).Should().Be("Hello World");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SecureString_PlusOperator_String()
|
||||
{
|
||||
var ss1 = new SecureString("Hello ");
|
||||
var ss2 = "World";
|
||||
|
||||
(ss1 + ss2).Should().Be("Hello World");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SecureString_PlusOperator_Char()
|
||||
{
|
||||
var ss1 = new SecureString("Hello ");
|
||||
var c = 'W';
|
||||
|
||||
(ss1 + c).Should().Be("Hello W");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SecureString_WithOptionalEntropy_Matches()
|
||||
{
|
||||
SecureString.AddOptionalEntropy(new byte[] { 10, 20, 25, 34, 56, 12, 10, 81, 200, 155, 123, 144, 123, 192, 122, 1 });
|
||||
var ss1 = new SecureString("Hello");
|
||||
var ss2 = new SecureString("Hello");
|
||||
|
||||
ss1.Should().Be(ss2);
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Hashing;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.NetStandard.Security.Tests;
|
||||
|
||||
[TestClass]
|
||||
public sealed class Sha256HashingServiceTests
|
||||
{
|
||||
private readonly IHashingService hashingService = new Sha256HashingService();
|
||||
private string toHashtString;
|
||||
private byte[] toHashtBytes;
|
||||
private Stream toHashStream;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
this.toHashtBytes = Encoding.UTF8.GetBytes("toEncrypt");
|
||||
this.toHashtString = Convert.ToBase64String(this.toHashtBytes);
|
||||
this.toHashStream = new MemoryStream(this.toHashtBytes);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task HashString()
|
||||
{
|
||||
var hash = await this.hashingService.Hash(this.toHashtString).ConfigureAwait(false);
|
||||
hash.Should().BeOfType<string>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task HashBytes()
|
||||
{
|
||||
var hash = await this.hashingService.Hash(this.toHashtBytes).ConfigureAwait(false);
|
||||
hash.Should().BeOfType<byte[]>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task HashStream()
|
||||
{
|
||||
var hash = await this.hashingService.Hash(this.toHashStream).ConfigureAwait(false);
|
||||
hash.Should().BeAssignableTo<Stream>();
|
||||
}
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.5.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.5.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SystemExtensions.NetStandard.Security\SystemExtensions.NetStandard.Security.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,226 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
using System.Security.Utilities;
|
||||
|
||||
namespace System.Security.Encryption;
|
||||
|
||||
public sealed class AesEncrypter : ISymmetricEncrypter, IDisposable
|
||||
{
|
||||
private readonly Aes aes;
|
||||
|
||||
public AesEncrypter()
|
||||
{
|
||||
this.aes = Aes.Create();
|
||||
}
|
||||
|
||||
public AesEncrypter(Aes aes)
|
||||
{
|
||||
this.aes = aes;
|
||||
}
|
||||
|
||||
public async Task<string> Decrypt(string key, string iv, string value)
|
||||
{
|
||||
using var valueStream = BytesToStream(StringToBytes(value));
|
||||
using var decryptedStream = await this.DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
|
||||
return StreamToString(decryptedStream);
|
||||
}
|
||||
|
||||
public async Task<string> Decrypt(byte[] key, byte[] iv, string value)
|
||||
{
|
||||
using var valueStream = BytesToStream(StringToBytes(value));
|
||||
using var decryptedStream = await this.DecryptInternal(key, iv, valueStream).ConfigureAwait(false);
|
||||
return StreamToString(decryptedStream);
|
||||
}
|
||||
|
||||
public async Task<byte[]> Decrypt(string key, string iv, byte[] value)
|
||||
{
|
||||
using var valueStream = BytesToStream(value);
|
||||
using var decryptedStream = await this.DecryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
|
||||
return StreamToBytes(decryptedStream);
|
||||
}
|
||||
|
||||
public async Task<byte[]> Decrypt(byte[] key, byte[] iv, byte[] value)
|
||||
{
|
||||
using var valueStream = BytesToStream(value);
|
||||
using var decryptedStream = await this.DecryptInternal(key, iv, valueStream).ConfigureAwait(false);
|
||||
return StreamToBytes(decryptedStream);
|
||||
}
|
||||
|
||||
public async Task<Stream> Decrypt(string key, string iv, Stream value)
|
||||
{
|
||||
return await this.DecryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<Stream> Decrypt(byte[] key, byte[] iv, Stream value)
|
||||
{
|
||||
return await this.DecryptInternal(key, iv, value).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<string> Encrypt(string key, string iv, string value)
|
||||
{
|
||||
using var valueStream = BytesToStream(StringToBytes(value));
|
||||
using var encryptedStream = await this.EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
|
||||
return StreamToString(encryptedStream);
|
||||
}
|
||||
|
||||
public async Task<string> Encrypt(byte[] key, byte[] iv, string value)
|
||||
{
|
||||
using var valueStream = BytesToStream(StringToBytes(value));
|
||||
using var encryptedStream = await this.EncryptInternal(key, iv, valueStream).ConfigureAwait(false);
|
||||
return StreamToString(encryptedStream);
|
||||
}
|
||||
|
||||
public async Task<byte[]> Encrypt(string key, string iv, byte[] value)
|
||||
{
|
||||
using var valueStream = BytesToStream(value);
|
||||
using var encryptedStream = await this.EncryptInternal(StringToBytes(key), StringToBytes(iv), valueStream).ConfigureAwait(false);
|
||||
return StreamToBytes(encryptedStream);
|
||||
}
|
||||
|
||||
public async Task<byte[]> Encrypt(byte[] key, byte[] iv, byte[] value)
|
||||
{
|
||||
using var valueStream = BytesToStream(value);
|
||||
using var encryptedStream = await this.EncryptInternal(key, iv, valueStream).ConfigureAwait(false);
|
||||
return StreamToBytes(encryptedStream);
|
||||
}
|
||||
|
||||
public async Task<Stream> Encrypt(string key, string iv, Stream value)
|
||||
{
|
||||
return value is null
|
||||
? throw new ArgumentNullException(nameof(value))
|
||||
: await this.EncryptInternal(StringToBytes(key), StringToBytes(iv), value).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<Stream> Encrypt(byte[] key, byte[] iv, Stream value)
|
||||
{
|
||||
return value is null
|
||||
? throw new ArgumentNullException(nameof(value))
|
||||
: await this.EncryptInternal(key, iv, value).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public Stream GetEncryptionStream(string key, string iv, Stream outStream)
|
||||
{
|
||||
return this.GetEncryptionStreamInternal(StringToBytes(key), StringToBytes(iv), outStream);
|
||||
}
|
||||
|
||||
public Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream)
|
||||
{
|
||||
return this.GetEncryptionStreamInternal(key, iv, outStream);
|
||||
}
|
||||
|
||||
public Stream GetDecryptionStream(string key, string iv, Stream inStream)
|
||||
{
|
||||
return this.GetDecryptionStreamInternal(StringToBytes(key), StringToBytes(iv), inStream);
|
||||
}
|
||||
|
||||
public Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream)
|
||||
{
|
||||
return this.GetDecryptionStreamInternal(key, iv, inStream);
|
||||
}
|
||||
|
||||
private async Task<Stream> EncryptInternal(byte[] key, byte[] iv, Stream toEncryptStream)
|
||||
{
|
||||
if (key.Length < 32)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(key)} must be at least 32 bytes");
|
||||
}
|
||||
|
||||
if (iv.Length < 16)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(iv)} must be at least 16 bytes");
|
||||
}
|
||||
|
||||
key = key.Take(32).ToArray();
|
||||
iv = iv.Take(16).ToArray();
|
||||
|
||||
|
||||
var encryptedMemoryStream = new MemoryStream();
|
||||
using var cryptoStream = this.GetEncryptionStreamInternal(key, iv, encryptedMemoryStream);
|
||||
await toEncryptStream.CopyToAsync(cryptoStream).ConfigureAwait(false);
|
||||
if (!cryptoStream.HasFlushedFinalBlock)
|
||||
{
|
||||
cryptoStream.FlushFinalBlock();
|
||||
}
|
||||
|
||||
encryptedMemoryStream.Position = 0;
|
||||
return encryptedMemoryStream;
|
||||
}
|
||||
|
||||
private async Task<Stream> DecryptInternal(byte[] key, byte[] iv, Stream toDecryptStream)
|
||||
{
|
||||
if (key.Length < 32)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(key)} must be at least 32 bytes");
|
||||
}
|
||||
|
||||
if (iv.Length < 16)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(iv)} must be at least 16 bytes");
|
||||
}
|
||||
|
||||
key = key.Take(32).ToArray();
|
||||
iv = iv.Take(16).ToArray();
|
||||
|
||||
|
||||
var decryptedMemoryStream = new MemoryStream();
|
||||
using var cryptoStream = this.GetDecryptionStreamInternal(key, iv, toDecryptStream);
|
||||
await cryptoStream.CopyToAsync(decryptedMemoryStream).ConfigureAwait(false);
|
||||
if (!cryptoStream.HasFlushedFinalBlock)
|
||||
{
|
||||
cryptoStream.FlushFinalBlock();
|
||||
}
|
||||
|
||||
decryptedMemoryStream.Position = 0;
|
||||
return decryptedMemoryStream;
|
||||
}
|
||||
|
||||
private CryptoStream GetEncryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream)
|
||||
{
|
||||
var crypto = this.aes.CreateEncryptor(key, iv);
|
||||
var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Write);
|
||||
return cryptoStream;
|
||||
}
|
||||
|
||||
private CryptoStream GetDecryptionStreamInternal(byte[] key, byte[] iv, Stream encryptedStream)
|
||||
{
|
||||
var crypto = this.aes.CreateDecryptor(key, iv);
|
||||
var cryptoStream = new NotClosingCryptoStream(encryptedStream, crypto, CryptoStreamMode.Read);
|
||||
return cryptoStream;
|
||||
}
|
||||
|
||||
private static byte[] StreamToBytes(Stream value)
|
||||
{
|
||||
value.Position = 0;
|
||||
var buffer = new byte[1024];
|
||||
using var ms = new MemoryStream();
|
||||
var read = -1;
|
||||
do
|
||||
{
|
||||
read = value.Read(buffer, 0, buffer.Length);
|
||||
ms.Write(buffer, 0, read);
|
||||
} while (read > 0);
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private static string StreamToString(Stream value)
|
||||
{
|
||||
return Convert.ToBase64String(StreamToBytes(value));
|
||||
}
|
||||
|
||||
private static byte[] StringToBytes(string value)
|
||||
{
|
||||
return Convert.FromBase64String(value);
|
||||
}
|
||||
|
||||
private static Stream BytesToStream(byte[] value)
|
||||
{
|
||||
return new MemoryStream(value);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.aes.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Security.Encryption;
|
||||
|
||||
public interface ISymmetricEncrypter
|
||||
{
|
||||
Stream GetEncryptionStream(string key, string iv, Stream outStream);
|
||||
Stream GetEncryptionStream(byte[] key, byte[] iv, Stream outStream);
|
||||
Stream GetDecryptionStream(string key, string iv, Stream inStream);
|
||||
Stream GetDecryptionStream(byte[] key, byte[] iv, Stream inStream);
|
||||
Task<string> Encrypt(string key, string iv, string value);
|
||||
Task<string> Encrypt(byte[] key, byte[] iv, string value);
|
||||
Task<byte[]> Encrypt(string key, string iv, byte[] value);
|
||||
Task<byte[]> Encrypt(byte[] key, byte[] iv, byte[] value);
|
||||
Task<Stream> Encrypt(string key, string iv, Stream value);
|
||||
Task<Stream> Encrypt(byte[] key, byte[] iv, Stream value);
|
||||
Task<string> Decrypt(string key, string iv, string value);
|
||||
Task<string> Decrypt(byte[] key, byte[] iv, string value);
|
||||
Task<byte[]> Decrypt(string key, string iv, byte[] value);
|
||||
Task<byte[]> Decrypt(byte[] key, byte[] iv, byte[] value);
|
||||
Task<Stream> Decrypt(string key, string iv, Stream value);
|
||||
Task<Stream> Decrypt(byte[] key, byte[] iv, Stream value);
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Security.Encryption;
|
||||
|
||||
public sealed class SecureString
|
||||
{
|
||||
private static byte[] optionalEntropy;
|
||||
private byte[] encryptedValue;
|
||||
|
||||
public string Value {
|
||||
get => this.encryptedValue is not null ? Encoding.UTF8.GetString(ProtectedData.Unprotect(this.encryptedValue, optionalEntropy, DataProtectionScope.CurrentUser)) : string.Empty;
|
||||
private set => this.encryptedValue = value is not null
|
||||
? ProtectedData.Protect(Encoding.UTF8.GetBytes(value), optionalEntropy, DataProtectionScope.CurrentUser)
|
||||
: null;
|
||||
}
|
||||
|
||||
public SecureString(string value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is string)
|
||||
{
|
||||
return this == (obj as string);
|
||||
}
|
||||
else if (obj is SecureString)
|
||||
{
|
||||
return this == (obj as SecureString);
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.Equals(obj);
|
||||
}
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.Value.GetHashCode();
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return this.Value;
|
||||
}
|
||||
|
||||
public static readonly SecureString Empty = new(null);
|
||||
public static implicit operator string(SecureString ss) => ss is null ? string.Empty : ss.Value;
|
||||
public static implicit operator SecureString(string s) => new(s);
|
||||
public static SecureString operator +(SecureString ss1, SecureString ss2)
|
||||
{
|
||||
if (ss1 is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(ss1));
|
||||
}
|
||||
|
||||
if (ss2 is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(ss2));
|
||||
}
|
||||
|
||||
return new SecureString(ss1.Value + ss2.Value);
|
||||
}
|
||||
public static SecureString operator +(SecureString ss1, string s2)
|
||||
{
|
||||
if (ss1 is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(ss1));
|
||||
}
|
||||
|
||||
return new SecureString(ss1.Value + s2);
|
||||
}
|
||||
public static SecureString operator +(SecureString ss1, char c)
|
||||
{
|
||||
if (ss1 is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(ss1));
|
||||
}
|
||||
|
||||
return new SecureString(ss1.Value + c);
|
||||
}
|
||||
public static bool operator ==(SecureString ss1, SecureString ss2)
|
||||
{
|
||||
if (ss1 is null && ss2 is null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return ss1?.Value == ss2?.Value;
|
||||
}
|
||||
public static bool operator !=(SecureString ss1, SecureString ss2)
|
||||
{
|
||||
return !(ss1 == ss2);
|
||||
}
|
||||
public static bool operator ==(SecureString ss1, string s2)
|
||||
{
|
||||
return ss1?.Value == s2;
|
||||
}
|
||||
public static bool operator !=(SecureString ss1, string s2)
|
||||
{
|
||||
return !(ss1?.Value == s2);
|
||||
}
|
||||
|
||||
public static void AddOptionalEntropy(byte[] entropy)
|
||||
{
|
||||
optionalEntropy = entropy;
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
public abstract class BaseHMACService<T> : IHMACService
|
||||
where T : HMAC
|
||||
{
|
||||
protected abstract T GetHashAlgorithm(byte[] key);
|
||||
|
||||
public async Task<string> Hash(string key, string raw)
|
||||
{
|
||||
using var rawStream = BytesToStream(StringToBytes(raw));
|
||||
var keyBytes = StringToBytes(key);
|
||||
using var hashedStream = await this.HashInternal(keyBytes, rawStream).ConfigureAwait(false);
|
||||
return StreamToString(hashedStream);
|
||||
}
|
||||
public async Task<byte[]> Hash(byte[] key, byte[] raw)
|
||||
{
|
||||
using var rawStream = BytesToStream(raw);
|
||||
using var hashedStream = await this.HashInternal(key, rawStream).ConfigureAwait(false);
|
||||
return StreamToBytes(hashedStream);
|
||||
}
|
||||
public async Task<Stream> Hash(byte[] key, Stream raw)
|
||||
{
|
||||
return await this.HashInternal(key, raw);
|
||||
}
|
||||
|
||||
private static byte[] StreamToBytes(Stream value)
|
||||
{
|
||||
value.Position = 0;
|
||||
var buffer = new byte[1024];
|
||||
using var ms = new MemoryStream();
|
||||
var read = -1;
|
||||
do
|
||||
{
|
||||
read = value.Read(buffer, 0, buffer.Length);
|
||||
ms.Write(buffer, 0, read);
|
||||
} while (read > 0);
|
||||
return ms.ToArray();
|
||||
}
|
||||
private static string StreamToString(Stream value)
|
||||
{
|
||||
return Convert.ToBase64String(StreamToBytes(value));
|
||||
}
|
||||
private static byte[] StringToBytes(string value)
|
||||
{
|
||||
return Convert.FromBase64String(value);
|
||||
}
|
||||
private static Stream BytesToStream(byte[] value)
|
||||
{
|
||||
return new MemoryStream(value);
|
||||
}
|
||||
private async Task<Stream> HashInternal(byte[] key, Stream raw)
|
||||
{
|
||||
if (raw is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(raw));
|
||||
}
|
||||
|
||||
using var algo = this.GetHashAlgorithm(key);
|
||||
return await Task.Run(() => new MemoryStream(algo.ComputeHash(raw)));
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
public abstract class BaseHashingService<T>
|
||||
where T : HashAlgorithm
|
||||
{
|
||||
protected abstract T GetHashAlgorithm();
|
||||
|
||||
public async Task<string> Hash(string raw)
|
||||
{
|
||||
using var rawStream = BytesToStream(StringToBytes(raw));
|
||||
using var hashedStream = await this.HashInternal(rawStream).ConfigureAwait(false);
|
||||
return StreamToString(hashedStream);
|
||||
}
|
||||
public async Task<byte[]> Hash(byte[] raw)
|
||||
{
|
||||
using var rawStream = BytesToStream(raw);
|
||||
using var hashedStream = await this.HashInternal(rawStream).ConfigureAwait(false);
|
||||
return StreamToBytes(hashedStream);
|
||||
}
|
||||
public async Task<Stream> Hash(Stream raw)
|
||||
{
|
||||
return await this.HashInternal(raw);
|
||||
}
|
||||
|
||||
private static byte[] StreamToBytes(Stream value)
|
||||
{
|
||||
value.Position = 0;
|
||||
var buffer = new byte[1024];
|
||||
using var ms = new MemoryStream();
|
||||
var read = -1;
|
||||
do
|
||||
{
|
||||
read = value.Read(buffer, 0, buffer.Length);
|
||||
ms.Write(buffer, 0, read);
|
||||
} while (read > 0);
|
||||
return ms.ToArray();
|
||||
}
|
||||
private static string StreamToString(Stream value)
|
||||
{
|
||||
return Convert.ToBase64String(StreamToBytes(value));
|
||||
}
|
||||
private static byte[] StringToBytes(string value)
|
||||
{
|
||||
return Convert.FromBase64String(value);
|
||||
}
|
||||
private static Stream BytesToStream(byte[] value)
|
||||
{
|
||||
return new MemoryStream(value);
|
||||
}
|
||||
private async Task<Stream> HashInternal(Stream raw)
|
||||
{
|
||||
if (raw is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(raw));
|
||||
}
|
||||
|
||||
using var algo = this.GetHashAlgorithm();
|
||||
return await Task.Run(() => new MemoryStream(algo.ComputeHash(raw)));
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
public sealed class HMACMD5Service : BaseHMACService<HMACMD5>, IHMACMD5Service
|
||||
{
|
||||
protected override HMACMD5 GetHashAlgorithm(byte[] key)
|
||||
{
|
||||
return new HMACMD5(key);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
public sealed class HMACSha1Service : BaseHMACService<HMACSHA1>, IHMACSha1Service
|
||||
{
|
||||
protected override HMACSHA1 GetHashAlgorithm(byte[] key)
|
||||
{
|
||||
return new HMACSHA1(key);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
public sealed class HMACSha256Service : BaseHMACService<HMACSHA256>, IHMACSha256Service
|
||||
{
|
||||
protected override HMACSHA256 GetHashAlgorithm(byte[] key)
|
||||
{
|
||||
return new HMACSHA256(key);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
public sealed class HMACSha384Service : BaseHMACService<HMACSHA384>, IHMACSha384Service
|
||||
{
|
||||
protected override HMACSHA384 GetHashAlgorithm(byte[] key)
|
||||
{
|
||||
return new HMACSHA384(key);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
public sealed class HMACSha512Service : BaseHMACService<HMACSHA512>, IHMACSha512Service
|
||||
{
|
||||
protected override HMACSHA512 GetHashAlgorithm(byte[] key)
|
||||
{
|
||||
return new HMACSHA512(key);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace System.Security.Hashing;
|
||||
public interface IHMACMD5Service : IHMACService
|
||||
{
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
public interface IHMACService
|
||||
{
|
||||
Task<string> Hash(string key, string raw);
|
||||
Task<byte[]> Hash(byte[] key, byte[] raw);
|
||||
Task<Stream> Hash(byte[] key, Stream raw);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace System.Security.Hashing;
|
||||
public interface IHMACSha1Service : IHMACService
|
||||
{
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace System.Security.Hashing;
|
||||
public interface IHMACSha256Service : IHMACService
|
||||
{
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace System.Security.Hashing;
|
||||
public interface IHMACSha384Service : IHMACService
|
||||
{
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace System.Security.Hashing;
|
||||
public interface IHMACSha512Service : IHMACService
|
||||
{
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
|
||||
public interface IHashingService
|
||||
{
|
||||
Task<string> Hash(string raw);
|
||||
Task<byte[]> Hash(byte[] raw);
|
||||
Task<Stream> Hash(Stream raw);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace System.Security.Hashing;
|
||||
public interface IMD5HashingService : IHashingService
|
||||
{
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
|
||||
public interface IPasswordHashingService
|
||||
{
|
||||
/// <summary>
|
||||
/// Hash provided raw password and return the hashed value.
|
||||
/// </summary>
|
||||
/// <param name="raw">Base64 encoded password.</param>
|
||||
/// <param name="salt">Base64 encoded salt to be used for hashing.</param>
|
||||
/// <param name="length">Length of the resulting hash.</param>
|
||||
/// <param name="iterations">Number of hashing iterations to be performed.</param>
|
||||
/// <remarks>
|
||||
/// The length of the hash will vary due to the base64 encoding of the resulting hash.
|
||||
/// </remarks>
|
||||
/// <returns>Base64 encoded hashed password.</returns>
|
||||
Task<string> Hash(string raw, string salt, int length, int iterations);
|
||||
/// <summary>
|
||||
/// Hash provided raw password and return the hashed value.
|
||||
/// </summary>
|
||||
/// <param name="raw">Password to be hashed.</param>
|
||||
/// <param name="salt">Salt to be used for hashing.</param>
|
||||
/// <param name="length">Length of the resulting hash.</param>
|
||||
/// <param name="iterations">Number of hashing iterations to be performed.</param>
|
||||
/// <returns>Hashed password.</returns>
|
||||
Task<byte[]> Hash(byte[] raw, byte[] salt, int length, int iterations);
|
||||
/// <summary>
|
||||
/// Verify provided password against a hashed password.
|
||||
/// </summary>
|
||||
/// <param name="hash">Base64 encoding of the previously hashed password.</param>
|
||||
/// <param name="password">Base64 encoding of the password to be verified.</param>
|
||||
/// <param name="salt">Salt used to hash the previous password.</param>
|
||||
/// <param name="iterations">Number of iterations used to hash the previous password.</param>
|
||||
/// <returns>Returns true if password matches the previously hashed password. Otherwise returns false.</returns>
|
||||
Task<bool> VerifyPassword(string hash, string password, string salt, int iterations);
|
||||
/// <summary>
|
||||
/// Verify provided password against a hashed password.
|
||||
/// </summary>
|
||||
/// <param name="hash">Previously hashed password.</param>
|
||||
/// <param name="password">Password to be verified.</param>
|
||||
/// <param name="salt">Salt used to hash the previous password.</param>
|
||||
/// <param name="iterations">Number of iterations used to hash the previous password.</param>
|
||||
/// <returns>Returns true if password matches the previously hashed password. Otherwise returns false.</returns>
|
||||
Task<bool> VerifyPassword(byte[] hash, byte[] password, byte[] salt, int iterations);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace System.Security.Hashing;
|
||||
public interface ISha1HashingService : IHashingService
|
||||
{
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace System.Security.Hashing;
|
||||
public interface ISha256HashingService : IHashingService
|
||||
{
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace System.Security.Hashing;
|
||||
public interface ISha384HashingService : IHashingService
|
||||
{
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace System.Security.Hashing;
|
||||
public interface ISha512HashingService : IHashingService
|
||||
{
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
public sealed class MD5HashingService : BaseHashingService<MD5>, IMD5HashingService
|
||||
{
|
||||
protected override MD5 GetHashAlgorithm()
|
||||
{
|
||||
return MD5.Create();
|
||||
}
|
||||
}
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
|
||||
public sealed class Rfc2898DeriveBytesPasswordHashingService : IPasswordHashingService
|
||||
{
|
||||
private const int MinimumIterations = 10000;
|
||||
private const int MinimumHashLength = 32;
|
||||
|
||||
public Rfc2898DeriveBytesPasswordHashingService()
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<string> Hash(string raw, string salt, int length, int iterations)
|
||||
{
|
||||
this.ValidateHashArguments(raw, salt, length, iterations);
|
||||
|
||||
var rawBytes = Convert.FromBase64String(raw);
|
||||
var saltBytes = Convert.FromBase64String(salt);
|
||||
var hashBytes = await this.HashInternal(rawBytes, saltBytes, length, iterations);
|
||||
return Convert.ToBase64String(hashBytes);
|
||||
}
|
||||
public Task<byte[]> Hash(byte[] raw, byte[] salt, int length, int iterations)
|
||||
{
|
||||
this.ValidateHashArguments(raw, salt, length, iterations);
|
||||
|
||||
return this.HashInternal(raw, salt, length, iterations);
|
||||
}
|
||||
public Task<bool> VerifyPassword(string hash, string password, string salt, int iterations)
|
||||
{
|
||||
this.ValidateVerifyArguments(hash, password, salt, iterations);
|
||||
var hashBytes = Convert.FromBase64String(hash);
|
||||
var saltBytes = Convert.FromBase64String(salt);
|
||||
var passwordBytes = Convert.FromBase64String(password);
|
||||
return this.VerifyPasswordInternal(hashBytes, passwordBytes, saltBytes, iterations);
|
||||
}
|
||||
public Task<bool> VerifyPassword(byte[] hash, byte[] password, byte[] salt, int iterations)
|
||||
{
|
||||
this.ValidateVerifyArguments(hash, password, salt, iterations);
|
||||
return this.VerifyPasswordInternal(hash, password, salt, iterations);
|
||||
}
|
||||
|
||||
private void ValidateHashArguments(object raw, object salt, int length, int iterations)
|
||||
{
|
||||
_ = raw ?? throw new ArgumentNullException(nameof(raw));
|
||||
_ = salt ?? throw new ArgumentNullException(nameof(salt));
|
||||
|
||||
if (iterations < MinimumIterations)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to perform secure hash. Iteration count must be over {MinimumIterations}");
|
||||
}
|
||||
|
||||
if (length < MinimumHashLength)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to perform secure hash. Hash length must be over {MinimumHashLength}");
|
||||
}
|
||||
}
|
||||
private void ValidateVerifyArguments(object hash, object password, object salt, int iterations)
|
||||
{
|
||||
_ = hash ?? throw new ArgumentNullException(nameof(hash));
|
||||
_ = salt ?? throw new ArgumentNullException(nameof(salt));
|
||||
_ = password ?? throw new ArgumentNullException(nameof(password));
|
||||
|
||||
if (iterations < MinimumIterations)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to verify hash. Iteration count must be over {MinimumIterations}");
|
||||
}
|
||||
}
|
||||
private Task<byte[]> HashInternal(byte[] raw, byte[] salt, int length, int iterations)
|
||||
{
|
||||
using var pbkdf2 = new Rfc2898DeriveBytes(raw, salt, iterations);
|
||||
var hash = pbkdf2.GetBytes(length);
|
||||
return Task.FromResult(hash);
|
||||
}
|
||||
private Task<bool> VerifyPasswordInternal(byte[] hash, byte[] password, byte[] salt, int iterations)
|
||||
{
|
||||
using var pbkdf2 = new Rfc2898DeriveBytes(password, salt, iterations);
|
||||
var hashToVerify = pbkdf2.GetBytes(hash.Length);
|
||||
var lengthToVerify = Math.Max(hash.Length, hashToVerify.Length);
|
||||
var match = true;
|
||||
if (lengthToVerify <= 0)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
for(var i = 0; i < lengthToVerify; i++)
|
||||
{
|
||||
if (i < hash.Length && i < hashToVerify.Length)
|
||||
{
|
||||
if (hashToVerify[i].Equals(hash[i]) is false)
|
||||
{
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(match && hash.Length.Equals(hashToVerify.Length));
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
public sealed class Sha1HashingService : BaseHashingService<SHA1>, ISha1HashingService
|
||||
{
|
||||
protected override SHA1 GetHashAlgorithm() => SHA1.Create();
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
|
||||
public sealed class Sha256HashingService : BaseHashingService<SHA256>, ISha256HashingService
|
||||
{
|
||||
protected override SHA256 GetHashAlgorithm() => SHA256.Create();
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
public sealed class Sha384HashingService : BaseHashingService<SHA384>, ISha384HashingService
|
||||
{
|
||||
protected override SHA384 GetHashAlgorithm()
|
||||
{
|
||||
return SHA384.Create();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace System.Security.Hashing;
|
||||
public sealed class Sha512HashingService : BaseHashingService<SHA512>, ISha512HashingService
|
||||
{
|
||||
protected override SHA512 GetHashAlgorithm() => SHA512.Create();
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Macocian Alexandru Victor
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,58 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace System.Security.Rng;
|
||||
|
||||
public sealed class CryptoRngProvider : ICryptoRngProvider, IDisposable
|
||||
{
|
||||
private readonly RNGCryptoServiceProvider rngProvider;
|
||||
private bool disposedValue;
|
||||
|
||||
public CryptoRngProvider()
|
||||
{
|
||||
this.rngProvider = new RNGCryptoServiceProvider();
|
||||
}
|
||||
public CryptoRngProvider(CspParameters cspParams)
|
||||
{
|
||||
this.rngProvider = new RNGCryptoServiceProvider(cspParams);
|
||||
}
|
||||
|
||||
|
||||
public void GetBytes(byte[] data)
|
||||
{
|
||||
this.rngProvider.GetBytes(data);
|
||||
}
|
||||
public void GetNonZeroBytes(byte[] data)
|
||||
{
|
||||
this.rngProvider.GetNonZeroBytes(data);
|
||||
}
|
||||
public byte[] GetBytes(int byteCount)
|
||||
{
|
||||
var bytes = new byte[byteCount];
|
||||
this.GetBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
public byte[] GetNonZeroBytes(int byteCount)
|
||||
{
|
||||
var bytes = new byte[byteCount];
|
||||
this.GetNonZeroBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!this.disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
this.rngProvider.Dispose();
|
||||
}
|
||||
|
||||
this.disposedValue = true;
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
namespace System.Security.Rng;
|
||||
|
||||
public interface ICryptoRngProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Populate provided array of bytes with cryptographically secure random bytes.
|
||||
/// </summary>
|
||||
/// <param name="data">Array of bytes to be populated.</param>
|
||||
public void GetBytes(byte[] data);
|
||||
/// <summary>
|
||||
/// Return an array of cryptographically secure random bytes.
|
||||
/// </summary>
|
||||
/// <param name="byteCount">Length of the returned array.</param>
|
||||
/// <returns>Array containing cryptographically secure random values.</returns>
|
||||
public byte[] GetBytes(int byteCount);
|
||||
/// <summary>
|
||||
/// Populate provided array of bytes with cryptographically secure random non-zero bytes.
|
||||
/// </summary>
|
||||
/// <param name="data">Array of bytes to be populated.</param>
|
||||
public void GetNonZeroBytes(byte[] data);
|
||||
/// <summary>
|
||||
/// Return an array of cryptographically secure random non-zero bytes.
|
||||
/// </summary>
|
||||
/// <param name="byteCount">Length of the returned array.</param>
|
||||
/// <returns>Array containing cryptographically secure random non-zero values.</returns>
|
||||
public byte[] GetNonZeroBytes(int byteCount);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<RootNamespace>System</RootNamespace>
|
||||
<Version>1.3.1</Version>
|
||||
<Authors>Alexandru Macocian</Authors>
|
||||
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
|
||||
<Description>Security extensions for the System namespace</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="../LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,22 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace System.Security.Utilities;
|
||||
|
||||
internal sealed class NotClosingCryptoStream : CryptoStream
|
||||
{
|
||||
public NotClosingCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode)
|
||||
: base(stream, transform, mode)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!this.HasFlushedFinalBlock)
|
||||
{
|
||||
this.FlushFinalBlock();
|
||||
}
|
||||
|
||||
base.Dispose(false);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Extensions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Cache;
|
||||
public sealed class AsyncValueCache<T>(Func<Task<T>> cacheRefreshOperation, TimeSpan cacheDuration)
|
||||
where T : class
|
||||
{
|
||||
private readonly Func<Task<T>> cacheRefreshOperation = cacheRefreshOperation.ThrowIfNull(nameof(cacheRefreshOperation));
|
||||
private readonly TimeSpan cacheDuration = cacheDuration;
|
||||
|
||||
private T? value;
|
||||
private DateTime lastCacheRefresh = DateTime.MinValue;
|
||||
|
||||
public async Task<T> GetValue()
|
||||
{
|
||||
if (DateTime.Now - this.lastCacheRefresh < this.cacheDuration &&
|
||||
this.value is not null)
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
|
||||
return await this.PerformCacheRefresh();
|
||||
}
|
||||
|
||||
public async Task<T> ForceCacheRefresh()
|
||||
{
|
||||
return await this.PerformCacheRefresh();
|
||||
}
|
||||
|
||||
private async Task<T> PerformCacheRefresh()
|
||||
{
|
||||
this.value = await this.cacheRefreshOperation();
|
||||
this.lastCacheRefresh = DateTime.Now;
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System.Extensions;
|
||||
|
||||
namespace System.Cache;
|
||||
public sealed class ValueCache<T>(Func<T> cacheRefreshOperation, TimeSpan cacheDuration)
|
||||
where T : class
|
||||
{
|
||||
private readonly Func<T> cacheRefreshOperation = cacheRefreshOperation.ThrowIfNull(nameof(cacheRefreshOperation));
|
||||
private readonly TimeSpan cacheDuration = cacheDuration;
|
||||
|
||||
private T? value;
|
||||
private DateTime lastCacheRefresh = DateTime.MinValue;
|
||||
|
||||
public T GetValue()
|
||||
{
|
||||
if (DateTime.Now - this.lastCacheRefresh < this.cacheDuration &&
|
||||
this.value is not null)
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
|
||||
return this.PerformCacheRefresh();
|
||||
}
|
||||
|
||||
public T ForceCacheRefresh()
|
||||
{
|
||||
return this.PerformCacheRefresh();
|
||||
}
|
||||
|
||||
private T PerformCacheRefresh()
|
||||
{
|
||||
this.value = this.cacheRefreshOperation();
|
||||
this.lastCacheRefresh = DateTime.Now;
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
@@ -1,401 +1,389 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// AVL tree implementation.
|
||||
/// Thanks to Karim Oumghar for the implementation example.
|
||||
/// Read on https://simpledevcode.wordpress.com/2014/09/16/avl-tree-in-c/
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class AVLTree<T> : ICollection<T> where T : IComparable<T>
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
#region Fields
|
||||
/// <summary>
|
||||
/// AVL tree implementation.
|
||||
/// Thanks to Karim Oumghar for the implementation example.
|
||||
/// Read on https://simpledevcode.wordpress.com/2014/09/16/avl-tree-in-c/
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
private class AVLNode<TKey>
|
||||
public sealed class AVLTree<T> : ICollection<T> where T : IComparable<T>
|
||||
{
|
||||
public TKey Value;
|
||||
public AVLNode<TKey> Left = default!;
|
||||
public AVLNode<TKey> Right = default!;
|
||||
public AVLNode(TKey value)
|
||||
#region Fields
|
||||
[Serializable]
|
||||
private class AVLNode<TKey>
|
||||
{
|
||||
this.Value = value;
|
||||
public TKey Value;
|
||||
public AVLNode<TKey> Left;
|
||||
public AVLNode<TKey> Right;
|
||||
public AVLNode(TKey value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
AVLNode<T> root = default!;
|
||||
private int count = 0;
|
||||
private readonly bool isReadOnly = false;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Count of items currently stored in the tree.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
AVLNode<T> root;
|
||||
private int count = 0;
|
||||
private readonly bool isReadOnly = false;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Count of items currently stored in the tree.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
return this.count;
|
||||
get
|
||||
{
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// True if the collection is readonly. False otherwise.
|
||||
/// </summary>
|
||||
public bool IsReadOnly => this.isReadOnly;
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initializes a new instance of an AVLTree collection.
|
||||
/// </summary>
|
||||
public AVLTree()
|
||||
{
|
||||
/// <summary>
|
||||
/// True if the collection is readonly. False otherwise.
|
||||
/// </summary>
|
||||
public bool IsReadOnly => isReadOnly;
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Initializes a new instance of an AVLTree collection.
|
||||
/// </summary>
|
||||
public AVLTree()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds the value to the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added to the tree.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
this.count++;
|
||||
var newItem = new AVLNode<T>(value);
|
||||
if (this.root == null)
|
||||
{
|
||||
this.root = newItem;
|
||||
}
|
||||
else
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds the value to the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added to the tree.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
this.root = this.RecursiveInsertion(this.root, newItem);
|
||||
count++;
|
||||
AVLNode<T> newItem = new AVLNode<T>(value);
|
||||
if (root == null)
|
||||
{
|
||||
root = newItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
root = RecursiveInsertion(root, newItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if the key is contained into the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be checked if present in the tree.</param>
|
||||
/// <returns>True if the value is in the tree.</returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
var node = this.Find(value, this.root);
|
||||
if (node == null)
|
||||
/// <summary>
|
||||
/// Checks if the key is contained into the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be checked if present in the tree.</param>
|
||||
/// <returns>True if the value is in the tree.</returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
return false;
|
||||
AVLNode<T> node = Find(value, root);
|
||||
if (node == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (node.Value.CompareTo(value) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.Value.CompareTo(value) == 0)
|
||||
/// <summary>
|
||||
/// Removes the specified value from the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be deleted.</param>
|
||||
public bool Remove(T value)
|
||||
{
|
||||
root = Delete(root, value);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
/// <summary>
|
||||
/// Clears the tree.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes the specified value from the tree.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be deleted.</param>
|
||||
public bool Remove(T value)
|
||||
{
|
||||
this.root = this.Delete(this.root, value)!;
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the tree.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
var queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(this.root);
|
||||
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(root);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var currentNode = queue.Dequeue();
|
||||
if (currentNode.Left != null)
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
currentNode.Left = default!;
|
||||
this.count--;
|
||||
AVLNode<T> currentNode = queue.Dequeue();
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
currentNode.Left = null;
|
||||
count--;
|
||||
}
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
currentNode.Right = null;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentNode.Right != null)
|
||||
root = null;
|
||||
count--;
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the tree onto the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to store the values in the tree.</param>
|
||||
/// <param name="arrayIndex">Starting index of the provided array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(root);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
currentNode.Right = default!;
|
||||
this.count--;
|
||||
AVLNode<T> currentNode = queue.Dequeue();
|
||||
array[arrayIndex++] = currentNode.Value;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.root = default!;
|
||||
this.count--;
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the tree onto the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to store the values in the tree.</param>
|
||||
/// <param name="arrayIndex">Starting index of the provided array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
var queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(this.root);
|
||||
while (queue.Count > 0)
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the tree.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
var currentNode = queue.Dequeue();
|
||||
array[arrayIndex++] = currentNode.Value;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
return GetEnumerator(root);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the tree.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return this.GetEnumerator(this.root);
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the tree structure into an array.
|
||||
/// </summary>
|
||||
/// <returns>Array containing the values contained in the tree.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
var array = new T[this.count];
|
||||
this.CopyTo(array, 0);
|
||||
return array;
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
private AVLNode<T> RecursiveInsertion(AVLNode<T> current, AVLNode<T> n)
|
||||
{
|
||||
if (current == null)
|
||||
/// <summary>
|
||||
/// Copies the tree structure into an array.
|
||||
/// </summary>
|
||||
/// <returns>Array containing the values contained in the tree.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
current = n;
|
||||
T[] array = new T[count];
|
||||
CopyTo(array, 0);
|
||||
return array;
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
private AVLNode<T> RecursiveInsertion(AVLNode<T> current, AVLNode<T> n)
|
||||
{
|
||||
if (current == null)
|
||||
{
|
||||
current = n;
|
||||
return current;
|
||||
}
|
||||
else if (n.Value.CompareTo(current.Value) < 0)
|
||||
{
|
||||
current.Left = RecursiveInsertion(current.Left, n);
|
||||
current = BalanceTree(current);
|
||||
}
|
||||
else if (n.Value.CompareTo(current.Value) > 0)
|
||||
{
|
||||
current.Right = RecursiveInsertion(current.Right, n);
|
||||
current = BalanceTree(current);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
else if (n.Value.CompareTo(current.Value) < 0)
|
||||
private AVLNode<T> BalanceTree(AVLNode<T> current)
|
||||
{
|
||||
current.Left = this.RecursiveInsertion(current.Left, n);
|
||||
current = this.BalanceTree(current);
|
||||
}
|
||||
else if (n.Value.CompareTo(current.Value) > 0)
|
||||
{
|
||||
current.Right = this.RecursiveInsertion(current.Right, n);
|
||||
current = this.BalanceTree(current);
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
private AVLNode<T> BalanceTree(AVLNode<T> current)
|
||||
{
|
||||
var b_factor = this.BalanceFactor(current);
|
||||
if (b_factor > 1)
|
||||
{
|
||||
if (this.BalanceFactor(current.Left) > 0)
|
||||
int b_factor = BalanceFactor(current);
|
||||
if (b_factor > 1)
|
||||
{
|
||||
current = this.RotateLL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = this.RotateLR(current);
|
||||
}
|
||||
}
|
||||
else if (b_factor < -1)
|
||||
{
|
||||
if (this.BalanceFactor(current.Right) > 0)
|
||||
{
|
||||
current = this.RotateRL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = this.RotateRR(current);
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
private AVLNode<T>? Delete(AVLNode<T> current, T target)
|
||||
{
|
||||
if (current == null)
|
||||
{ return null; }
|
||||
else
|
||||
{
|
||||
//left subtree
|
||||
if (target.CompareTo(current.Value) < 0)
|
||||
{
|
||||
current.Left = this.Delete(current.Left, target)!;
|
||||
if (this.BalanceFactor(current) == -2)//here
|
||||
if (BalanceFactor(current.Left) > 0)
|
||||
{
|
||||
if (this.BalanceFactor(current.Right) <= 0)
|
||||
{
|
||||
current = this.RotateRR(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = this.RotateRL(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
//right subtree
|
||||
else if (target.CompareTo(current.Value) > 0)
|
||||
{
|
||||
current.Right = this.Delete(current.Right, target)!;
|
||||
if (this.BalanceFactor(current) == 2)
|
||||
{
|
||||
if (this.BalanceFactor(current.Left) >= 0)
|
||||
{
|
||||
current = this.RotateLL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = this.RotateLR(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
//if target is found
|
||||
else
|
||||
{
|
||||
this.count--;
|
||||
if (current.Right != null)
|
||||
{
|
||||
//delete its inorder successor
|
||||
var parent = current.Right;
|
||||
while (parent.Left != null)
|
||||
{
|
||||
parent = parent.Left;
|
||||
}
|
||||
|
||||
current.Value = parent.Value;
|
||||
current.Right = this.Delete(current.Right, parent.Value)!;
|
||||
if (this.BalanceFactor(current) == 2)//rebalancing
|
||||
{
|
||||
if (this.BalanceFactor(current.Left) >= 0)
|
||||
{
|
||||
current = this.RotateLL(current);
|
||||
}
|
||||
else { current = this.RotateLR(current); }
|
||||
}
|
||||
current = RotateLL(current);
|
||||
}
|
||||
else
|
||||
{ //if current.left != null
|
||||
return current.Left;
|
||||
{
|
||||
current = RotateLR(current);
|
||||
}
|
||||
}
|
||||
else if (b_factor < -1)
|
||||
{
|
||||
if (BalanceFactor(current.Right) > 0)
|
||||
{
|
||||
current = RotateRL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = RotateRR(current);
|
||||
}
|
||||
}
|
||||
return current;
|
||||
}
|
||||
private AVLNode<T> Delete(AVLNode<T> current, T target)
|
||||
{
|
||||
AVLNode<T> parent;
|
||||
if (current == null)
|
||||
{ return null; }
|
||||
else
|
||||
{
|
||||
//left subtree
|
||||
if (target.CompareTo(current.Value) < 0)
|
||||
{
|
||||
current.Left = Delete(current.Left, target);
|
||||
if (BalanceFactor(current) == -2)//here
|
||||
{
|
||||
if (BalanceFactor(current.Right) <= 0)
|
||||
{
|
||||
current = RotateRR(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = RotateRL(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
//right subtree
|
||||
else if (target.CompareTo(current.Value) > 0)
|
||||
{
|
||||
current.Right = Delete(current.Right, target);
|
||||
if (BalanceFactor(current) == 2)
|
||||
{
|
||||
if (BalanceFactor(current.Left) >= 0)
|
||||
{
|
||||
current = RotateLL(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = RotateLR(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
//if target is found
|
||||
else
|
||||
{
|
||||
count--;
|
||||
if (current.Right != null)
|
||||
{
|
||||
//delete its inorder successor
|
||||
parent = current.Right;
|
||||
while (parent.Left != null)
|
||||
{
|
||||
parent = parent.Left;
|
||||
}
|
||||
current.Value = parent.Value;
|
||||
current.Right = Delete(current.Right, parent.Value);
|
||||
if (BalanceFactor(current) == 2)//rebalancing
|
||||
{
|
||||
if (BalanceFactor(current.Left) >= 0)
|
||||
{
|
||||
current = RotateLL(current);
|
||||
}
|
||||
else { current = RotateLR(current); }
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //if current.left != null
|
||||
return current.Left;
|
||||
}
|
||||
}
|
||||
}
|
||||
return current;
|
||||
}
|
||||
private AVLNode<T> Find(T target, AVLNode<T> current)
|
||||
{
|
||||
if (current == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (target.CompareTo(current.Value) < 0)
|
||||
{
|
||||
if (target.CompareTo(current.Value) == 0)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
else
|
||||
return Find(target, current.Left);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target.CompareTo(current.Value) == 0)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
else
|
||||
return Find(target, current.Right);
|
||||
}
|
||||
|
||||
}
|
||||
private int Max(int l, int r)
|
||||
{
|
||||
return l > r ? l : r;
|
||||
}
|
||||
private int GetHeight(AVLNode<T> current)
|
||||
{
|
||||
int height = 0;
|
||||
if (current != null)
|
||||
{
|
||||
int l = GetHeight(current.Left);
|
||||
int r = GetHeight(current.Right);
|
||||
int m = Max(l, r);
|
||||
height = m + 1;
|
||||
}
|
||||
return height;
|
||||
}
|
||||
private int BalanceFactor(AVLNode<T> current)
|
||||
{
|
||||
int l = GetHeight(current.Left);
|
||||
int r = GetHeight(current.Right);
|
||||
int b_factor = l - r;
|
||||
return b_factor;
|
||||
}
|
||||
private AVLNode<T> RotateRR(AVLNode<T> parent)
|
||||
{
|
||||
AVLNode<T> pivot = parent.Right;
|
||||
parent.Right = pivot.Left;
|
||||
pivot.Left = parent;
|
||||
return pivot;
|
||||
}
|
||||
private AVLNode<T> RotateLL(AVLNode<T> parent)
|
||||
{
|
||||
AVLNode<T> pivot = parent.Left;
|
||||
parent.Left = pivot.Right;
|
||||
pivot.Right = parent;
|
||||
return pivot;
|
||||
}
|
||||
private AVLNode<T> RotateLR(AVLNode<T> parent)
|
||||
{
|
||||
AVLNode<T> pivot = parent.Left;
|
||||
parent.Left = RotateRR(pivot);
|
||||
return RotateLL(parent);
|
||||
}
|
||||
private AVLNode<T> RotateRL(AVLNode<T> parent)
|
||||
{
|
||||
AVLNode<T> pivot = parent.Right;
|
||||
parent.Right = RotateLL(pivot);
|
||||
return RotateRR(parent);
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private IEnumerator<T> GetEnumerator(AVLNode<T> rootNode)
|
||||
{
|
||||
Queue<AVLNode<T>> queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(rootNode);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
AVLNode<T> currentNode = queue.Dequeue();
|
||||
yield return currentNode.Value;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return current;
|
||||
#endregion
|
||||
}
|
||||
private AVLNode<T>? Find(T target, AVLNode<T> current)
|
||||
{
|
||||
if (current == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (target.CompareTo(current.Value) < 0)
|
||||
{
|
||||
if (target.CompareTo(current.Value) == 0)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.Find(target, current.Left);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target.CompareTo(current.Value) == 0)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.Find(target, current.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
private int Max(int l, int r)
|
||||
{
|
||||
return l > r ? l : r;
|
||||
}
|
||||
private int GetHeight(AVLNode<T> current)
|
||||
{
|
||||
var height = 0;
|
||||
if (current != null)
|
||||
{
|
||||
var l = this.GetHeight(current.Left);
|
||||
var r = this.GetHeight(current.Right);
|
||||
var m = this.Max(l, r);
|
||||
height = m + 1;
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
private int BalanceFactor(AVLNode<T> current)
|
||||
{
|
||||
var l = this.GetHeight(current.Left);
|
||||
var r = this.GetHeight(current.Right);
|
||||
var b_factor = l - r;
|
||||
return b_factor;
|
||||
}
|
||||
private AVLNode<T> RotateRR(AVLNode<T> parent)
|
||||
{
|
||||
var pivot = parent.Right;
|
||||
parent.Right = pivot.Left;
|
||||
pivot.Left = parent;
|
||||
return pivot;
|
||||
}
|
||||
private AVLNode<T> RotateLL(AVLNode<T> parent)
|
||||
{
|
||||
var pivot = parent.Left;
|
||||
parent.Left = pivot.Right;
|
||||
pivot.Right = parent;
|
||||
return pivot;
|
||||
}
|
||||
private AVLNode<T> RotateLR(AVLNode<T> parent)
|
||||
{
|
||||
var pivot = parent.Left;
|
||||
parent.Left = this.RotateRR(pivot);
|
||||
return this.RotateLL(parent);
|
||||
}
|
||||
private AVLNode<T> RotateRL(AVLNode<T> parent)
|
||||
{
|
||||
var pivot = parent.Right;
|
||||
parent.Right = this.RotateLL(pivot);
|
||||
return this.RotateRR(parent);
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private IEnumerator<T> GetEnumerator(AVLNode<T> rootNode)
|
||||
{
|
||||
var queue = new Queue<AVLNode<T>>();
|
||||
queue.Enqueue(rootNode);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var currentNode = queue.Dequeue();
|
||||
yield return currentNode.Value;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,219 +1,214 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Binary heap implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class BinaryHeap<T> : IEnumerable<T> where T : IComparable<T>
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
#region Fields
|
||||
T[] items;
|
||||
private int capacity;
|
||||
private int count;
|
||||
private readonly int initialCapacity;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Minimum value from the heap.
|
||||
/// Binary heap implementation.
|
||||
/// </summary>
|
||||
public T Min
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class BinaryHeap<T> : IEnumerable<T> where T : IComparable<T>
|
||||
{
|
||||
get
|
||||
#region Fields
|
||||
T[] items;
|
||||
private int capacity;
|
||||
private int count;
|
||||
private readonly int initialCapacity;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Minimum value from the heap.
|
||||
/// </summary>
|
||||
public T Min
|
||||
{
|
||||
return this.items[1];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Maximum value from the heap.
|
||||
/// </summary>
|
||||
public T Max
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.items[this.count];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Capacity of the heap.
|
||||
/// </summary>
|
||||
public int Capacity
|
||||
{
|
||||
get => this.capacity;
|
||||
set
|
||||
{
|
||||
if (value > this.capacity)
|
||||
get
|
||||
{
|
||||
Array.Resize(ref this.items, value);
|
||||
this.capacity = value;
|
||||
return items[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Number of elements in the heap.
|
||||
/// </summary>
|
||||
public int Count { get => this.count; }
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
public BinaryHeap()
|
||||
{
|
||||
this.capacity = 10;
|
||||
this.initialCapacity = this.capacity;
|
||||
this.items = new T[this.capacity];
|
||||
}
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
/// <param name="capacity">Initial capacity of the heap. Used for initial alocation of the array.</param>
|
||||
public BinaryHeap(int capacity)
|
||||
{
|
||||
this.capacity = capacity;
|
||||
this.initialCapacity = capacity;
|
||||
this.items = new T[capacity];
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds value to the queue.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
if (this.count == this.Capacity - 1)
|
||||
/// <summary>
|
||||
/// Maximum value from the heap.
|
||||
/// </summary>
|
||||
public T Max
|
||||
{
|
||||
this.Capacity = 2 * this.Capacity;
|
||||
}
|
||||
|
||||
var position = ++this.count;
|
||||
for (; position > 1 && value.CompareTo(this.items[position / 2]) < 0; position /= 2)
|
||||
{
|
||||
this.items[position] = this.items[position / 2];
|
||||
}
|
||||
|
||||
this.items[position] = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes the item at the root. Throws exception if there are no items in the heap.
|
||||
/// </summary>
|
||||
/// <returns>Value removed.</returns>
|
||||
public T Remove()
|
||||
{
|
||||
if (this.count == 0)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Heap is empty!");
|
||||
}
|
||||
|
||||
var min = this.items[1];
|
||||
this.items[1] = this.items[this.count--];
|
||||
this.BubbleDown(1);
|
||||
return min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Peeks at the item at the root. Throws exception if there are no items in the heap.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public T Peek()
|
||||
{
|
||||
if (this.count == 0)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Heap is empty!");
|
||||
}
|
||||
|
||||
var min = this.items[1];
|
||||
return min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Return the heap structure as an array
|
||||
/// </summary>
|
||||
/// <returns>Array with values sorted as in heap</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
var newArray = new T[this.count];
|
||||
Array.Copy(this.items, 1, newArray, 0, this.count);
|
||||
return newArray;
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines whether the heap contains specified value
|
||||
/// </summary>
|
||||
/// <param name="value">Value to locate in the heap</param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
return this.items.Contains(value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the heap
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
this.count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the heap.
|
||||
/// </summary>
|
||||
/// <param name="completeClear">Specifies if the underlying array should be cleared as well</param>
|
||||
public void Clear(bool completeClear)
|
||||
{
|
||||
this.count = 0;
|
||||
if (completeClear)
|
||||
{
|
||||
this.capacity = this.initialCapacity;
|
||||
this.items = new T[this.initialCapacity];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates over the heap.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the heap.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < this.count; i++)
|
||||
{
|
||||
yield return this.items[i + 1];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Bubble the specified element to its position
|
||||
/// </summary>
|
||||
/// <param name="index">Index of element to bubble</param>
|
||||
private void BubbleDown(int index)
|
||||
{
|
||||
var temp = this.items[index];
|
||||
int childIndex;
|
||||
for (; 2 * index <= this.count; index = childIndex)
|
||||
{
|
||||
childIndex = 2 * index;
|
||||
if (childIndex != this.Count && this.items[childIndex].CompareTo(this.items[childIndex + 1]) > 0)
|
||||
get
|
||||
{
|
||||
childIndex++;
|
||||
}
|
||||
|
||||
if (temp.CompareTo(this.items[childIndex]) > 0)
|
||||
{
|
||||
this.items[index] = this.items[childIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
return items[count];
|
||||
}
|
||||
}
|
||||
|
||||
this.items[index] = temp;
|
||||
/// <summary>
|
||||
/// Capacity of the heap.
|
||||
/// </summary>
|
||||
public int Capacity
|
||||
{
|
||||
get => capacity;
|
||||
set
|
||||
{
|
||||
if (value > capacity)
|
||||
{
|
||||
Array.Resize(ref items, value);
|
||||
capacity = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Number of elements in the heap.
|
||||
/// </summary>
|
||||
public int Count { get => count; }
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
public BinaryHeap()
|
||||
{
|
||||
capacity = 10;
|
||||
initialCapacity = capacity;
|
||||
items = new T[capacity];
|
||||
}
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
/// <param name="capacity">Initial capacity of the heap. Used for initial alocation of the array.</param>
|
||||
public BinaryHeap(int capacity)
|
||||
{
|
||||
this.capacity = capacity;
|
||||
initialCapacity = capacity;
|
||||
items = new T[capacity];
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds value to the queue.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
if (count == Capacity - 1)
|
||||
{
|
||||
Capacity = 2 * Capacity;
|
||||
}
|
||||
int position = ++count;
|
||||
for (; position > 1 && value.CompareTo(items[position / 2]) < 0; position /= 2)
|
||||
{
|
||||
items[position] = items[position / 2];
|
||||
}
|
||||
items[position] = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes the item at the root. Throws exception if there are no items in the heap.
|
||||
/// </summary>
|
||||
/// <returns>Value removed.</returns>
|
||||
public T Remove()
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Heap is empty!");
|
||||
}
|
||||
T min = items[1];
|
||||
items[1] = items[count--];
|
||||
BubbleDown(1);
|
||||
return min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Peeks at the item at the root. Throws exception if there are no items in the heap.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public T Peek()
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Heap is empty!");
|
||||
}
|
||||
T min = items[1];
|
||||
return min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Return the heap structure as an array
|
||||
/// </summary>
|
||||
/// <returns>Array with values sorted as in heap</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
T[] newArray = new T[count];
|
||||
Array.Copy(items, 1, newArray, 0, count);
|
||||
return newArray;
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines whether the heap contains specified value
|
||||
/// </summary>
|
||||
/// <param name="value">Value to locate in the heap</param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
return items.Contains(value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the heap
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the heap.
|
||||
/// </summary>
|
||||
/// <param name="completeClear">Specifies if the underlying array should be cleared as well</param>
|
||||
public void Clear(bool completeClear)
|
||||
{
|
||||
count = 0;
|
||||
if (completeClear)
|
||||
{
|
||||
capacity = initialCapacity;
|
||||
items = new T[initialCapacity];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates over the heap.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the heap.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
yield return items[i + 1];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Bubble the specified element to its position
|
||||
/// </summary>
|
||||
/// <param name="index">Index of element to bubble</param>
|
||||
private void BubbleDown(int index)
|
||||
{
|
||||
T temp = items[index];
|
||||
int childIndex;
|
||||
for (; 2 * index <= count; index = childIndex)
|
||||
{
|
||||
childIndex = 2 * index;
|
||||
if (childIndex != Count && items[childIndex].CompareTo(items[childIndex + 1]) > 0)
|
||||
{
|
||||
childIndex++;
|
||||
}
|
||||
if (temp.CompareTo(items[childIndex]) > 0)
|
||||
{
|
||||
items[index] = items[childIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
items[index] = temp;
|
||||
}
|
||||
/// <summary>
|
||||
/// Implementation of IEnumerator.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator over the array.</returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
/// <summary>
|
||||
/// Implementation of IEnumerator.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator over the array.</returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Collections.Generic;
|
||||
public sealed class CircularBuffer<T> : IList<T>
|
||||
{
|
||||
private readonly T[] buffer;
|
||||
private int head;
|
||||
private int tail;
|
||||
|
||||
public int Count { get; private set; }
|
||||
public bool IsReadOnly { get; } = false;
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index > this.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
return this.buffer[(this.head + index) % this.buffer.Length];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (index > this.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
this.buffer[(this.head + index) % this.buffer.Length] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public CircularBuffer(int capacity)
|
||||
{
|
||||
if (capacity < 1) throw new ArgumentException($"{nameof(capacity)} cannot be smaller than 1");
|
||||
|
||||
this.buffer = new T[capacity];
|
||||
this.head = 0;
|
||||
this.tail = 0;
|
||||
}
|
||||
|
||||
public CircularBuffer(T[] buffer, int head, int tail)
|
||||
{
|
||||
if (buffer.Length == 0) throw new ArgumentException($"{nameof(buffer)} cannot be of length 0");
|
||||
|
||||
this.buffer = buffer;
|
||||
this.head = head;
|
||||
this.tail = tail;
|
||||
this.Count = this.tail < this.head ?
|
||||
this.tail + this.buffer.Length - this.head + 1 :
|
||||
this.tail - this.head + 1;
|
||||
}
|
||||
|
||||
public CircularBuffer(T[] buffer)
|
||||
{
|
||||
if (buffer.Length == 0) throw new ArgumentException($"{nameof(buffer)} cannot be of length 0");
|
||||
|
||||
this.buffer = buffer;
|
||||
this.head = 0;
|
||||
this.tail = this.buffer.Length - 1;
|
||||
this.Count = this.buffer.Length;
|
||||
}
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
if (this.Count == this.buffer.Length)
|
||||
{
|
||||
this.buffer[this.tail] = item;
|
||||
this.tail = (this.tail + 1) % this.buffer.Length;
|
||||
this.head = (this.head + 1) % this.buffer.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.buffer[this.tail] = item;
|
||||
this.tail = (this.tail + 1) % this.buffer.Length;
|
||||
this.Count++;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
this.head = 0;
|
||||
this.tail = 0;
|
||||
this.Count = 0;
|
||||
}
|
||||
|
||||
public void DeepClear()
|
||||
{
|
||||
this.Clear();
|
||||
Array.Clear(this.buffer, 0, this.buffer.Length);
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
var comparer = EqualityComparer<T>.Default;
|
||||
foreach(var itItem in this)
|
||||
{
|
||||
if (comparer.Equals(itItem, item))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Remove(T item)
|
||||
{
|
||||
var index = this.head;
|
||||
var comparer = EqualityComparer<T>.Default;
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (comparer.Equals(this.buffer[index % this.buffer.Length], item))
|
||||
{
|
||||
int nextIndex;
|
||||
for (var j = 0; j < this.Count - i - 1; j++)
|
||||
{
|
||||
nextIndex = (index + 1) % this.buffer.Length;
|
||||
this.buffer[index] = this.buffer[nextIndex];
|
||||
index = nextIndex;
|
||||
}
|
||||
|
||||
this.Count--;
|
||||
this.tail = this.tail == 0 ? this.buffer.Length - 1 : this.tail - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
index = (index + 1) % this.buffer.Length;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
foreach(var item in this)
|
||||
{
|
||||
array[arrayIndex++] = item;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
var index = this.head;
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
yield return this.buffer[index];
|
||||
index = (index + 1) % this.buffer.Length;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.GetEnumerator();
|
||||
}
|
||||
|
||||
public int IndexOf(T item)
|
||||
{
|
||||
var comparer = EqualityComparer<T>.Default;
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (comparer.Equals(this[i], item))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void Insert(int index, T item)
|
||||
{
|
||||
if (index < 0 || index > this.Count) throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
if (this.Count == this.buffer.Length) throw new InvalidOperationException("Cannot insert into a full buffer.");
|
||||
|
||||
if (index == this.Count)
|
||||
{
|
||||
this.Add(item);
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = this.Count; i > index; i--)
|
||||
{
|
||||
this.buffer[(this.head + i) % this.buffer.Length] = this.buffer[(this.head + i - 1) % this.buffer.Length];
|
||||
}
|
||||
|
||||
this.buffer[(this.head + index) % this.buffer.Length] = item;
|
||||
this.tail = (this.tail + 1) % this.buffer.Length;
|
||||
this.Count++;
|
||||
}
|
||||
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
if (index < 0 || index >= this.Count) throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
for (var i = index; i < this.Count - 1; i++)
|
||||
{
|
||||
this.buffer[(this.head + i) % this.buffer.Length] = this.buffer[(this.head + i + 1) % this.buffer.Length];
|
||||
}
|
||||
|
||||
this.tail = (this.tail - 1 + this.buffer.Length) % this.buffer.Length;
|
||||
this.Count--;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,38 +1,39 @@
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for queue implementations.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
public interface IQueue<T> : IEnumerable<T>
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the number of items in the queue.
|
||||
/// Interface for queue implementations.
|
||||
/// </summary>
|
||||
int Count { get; }
|
||||
/// <summary>
|
||||
/// Inserts item into the queue.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be inserted.</param>
|
||||
void Enqueue(T item);
|
||||
/// <summary>
|
||||
/// Remove the first item in the queue.
|
||||
/// </summary>
|
||||
/// <returns>First item in the queue.</returns>
|
||||
T Dequeue();
|
||||
/// <summary>
|
||||
/// Looks up the first item from the queue without removing it.
|
||||
/// </summary>
|
||||
/// <returns>First item from the queue.</returns>
|
||||
T Peek();
|
||||
/// <summary>
|
||||
/// Clears the contents of the queue.
|
||||
/// </summary>
|
||||
void Clear();
|
||||
/// <summary>
|
||||
/// Checks if queue contains an item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if queue contains provided item. False otherwise.</returns>
|
||||
bool Contains(T item);
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
public interface IQueue<T> : IEnumerable<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the number of items in the queue.
|
||||
/// </summary>
|
||||
int Count { get; }
|
||||
/// <summary>
|
||||
/// Inserts item into the queue.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be inserted.</param>
|
||||
void Enqueue(T item);
|
||||
/// <summary>
|
||||
/// Remove the first item in the queue.
|
||||
/// </summary>
|
||||
/// <returns>First item in the queue.</returns>
|
||||
T Dequeue();
|
||||
/// <summary>
|
||||
/// Looks up the first item from the queue without removing it.
|
||||
/// </summary>
|
||||
/// <returns>First item from the queue.</returns>
|
||||
T Peek();
|
||||
/// <summary>
|
||||
/// Clears the contents of the queue.
|
||||
/// </summary>
|
||||
void Clear();
|
||||
/// <summary>
|
||||
/// Checks if queue contains an item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if queue contains provided item. False otherwise.</returns>
|
||||
bool Contains(T item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,102 +1,103 @@
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Priority Queue data structure. The implementation is based on an array-based implementation of Binary Heap.
|
||||
/// Exposes some of the functionality of the Binary Heap as a queue.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class PriorityQueue<T> : IQueue<T> where T : IComparable<T>
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
#region Fields
|
||||
private readonly BinaryHeap<T> binaryHeap;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Returns the number of elements stored into the queue.
|
||||
/// Priority Queue data structure. The implementation is based on an array-based implementation of Binary Heap.
|
||||
/// Exposes some of the functionality of the Binary Heap as a queue.
|
||||
/// </summary>
|
||||
public int Count
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class PriorityQueue<T> : IQueue<T> where T : IComparable<T>
|
||||
{
|
||||
get
|
||||
#region Fields
|
||||
private readonly BinaryHeap<T> binaryHeap;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Returns the number of elements stored into the queue.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
return this.binaryHeap.Count;
|
||||
get
|
||||
{
|
||||
return binaryHeap.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for priority queue data structure.
|
||||
/// </summary>
|
||||
public PriorityQueue()
|
||||
{
|
||||
this.binaryHeap = new BinaryHeap<T>();
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Add provided value to the queue.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added to the queue.</param>
|
||||
public void Enqueue(T value)
|
||||
{
|
||||
this.binaryHeap.Add(value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Pops the queue and removes the highest priority value from the queue.
|
||||
/// </summary>
|
||||
/// <returns>Highest priority value from the queue</returns>
|
||||
public T Dequeue()
|
||||
{
|
||||
if (this.Count > 0)
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for priority queue data structure.
|
||||
/// </summary>
|
||||
public PriorityQueue()
|
||||
{
|
||||
return this.binaryHeap.Remove();
|
||||
binaryHeap = new BinaryHeap<T>();
|
||||
}
|
||||
else
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Add provided value to the queue.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added to the queue.</param>
|
||||
public void Enqueue(T value)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Queue is empty!");
|
||||
binaryHeap.Add(value);
|
||||
}
|
||||
/// <summary>
|
||||
/// Pops the queue and removes the highest priority value from the queue.
|
||||
/// </summary>
|
||||
/// <returns>Highest priority value from the queue</returns>
|
||||
public T Dequeue()
|
||||
{
|
||||
if (Count > 0)
|
||||
{
|
||||
return binaryHeap.Remove();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IndexOutOfRangeException("Queue is empty!");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Looks up the highest priority value from the queue. Doesn't alter the queue in any way.
|
||||
/// </summary>
|
||||
/// <returns>Highest priority value from the queue.</returns>
|
||||
public T Peek()
|
||||
{
|
||||
return binaryHeap.Min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the queue contents, removing any value stored into the queue.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
binaryHeap.Clear();
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if queue contains provided item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if queue contains the provided item. False otherwise.</returns>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return binaryHeap.Contains(item);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates over the queue.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the queue.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return binaryHeap.GetEnumerator();
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Necesarry for the implementatio of IQueue.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
/// <summary>
|
||||
/// Looks up the highest priority value from the queue. Doesn't alter the queue in any way.
|
||||
/// </summary>
|
||||
/// <returns>Highest priority value from the queue.</returns>
|
||||
public T Peek()
|
||||
{
|
||||
return this.binaryHeap.Min;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the queue contents, removing any value stored into the queue.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
this.binaryHeap.Clear();
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if queue contains provided item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if queue contains the provided item. False otherwise.</returns>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return this.binaryHeap.Contains(item);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates over the queue.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the queue.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return this.binaryHeap.GetEnumerator();
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Necesarry for the implementatio of IQueue.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,248 +1,236 @@
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Skip list implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class SkipList<T> : ICollection<T> where T : IComparable<T>
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
#region Fields
|
||||
/// <summary>
|
||||
/// Skip list implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
private class NodeSet<TKey>
|
||||
public sealed class SkipList<T> : ICollection<T> where T : IComparable<T>
|
||||
{
|
||||
public TKey Key;
|
||||
public int Level;
|
||||
public NodeSet<TKey>[] Next;
|
||||
#region Fields
|
||||
[Serializable]
|
||||
private class NodeSet<TKey>
|
||||
{
|
||||
public TKey Key;
|
||||
public int Level;
|
||||
public NodeSet<TKey>[] Next;
|
||||
|
||||
public NodeSet(TKey key, int level)
|
||||
{
|
||||
this.Key = key;
|
||||
this.Level = level;
|
||||
this.Next = new NodeSet<TKey>[level + 1];
|
||||
}
|
||||
}
|
||||
private int count;
|
||||
private readonly Random random;
|
||||
private readonly NodeSet<T> head;
|
||||
private readonly NodeSet<T> end;
|
||||
private readonly int maxLevel = 10;
|
||||
private int level;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Number of elements in the list.
|
||||
/// </summary>
|
||||
public int Count { get => this.count; }
|
||||
/// <summary>
|
||||
/// Specifies if the collection can be modified.
|
||||
/// </summary>
|
||||
public bool IsReadOnly { get; set; }
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates a new instance of SkipList collection.
|
||||
/// </summary>
|
||||
/// <param name="maxLevel">Maximum level of the skip list.</param>
|
||||
public SkipList(int maxLevel = 10)
|
||||
{
|
||||
this.maxLevel = maxLevel;
|
||||
this.random = new Random();
|
||||
this.head = new NodeSet<T>(default!, maxLevel);
|
||||
this.end = this.head;
|
||||
for (var i = 0; i <= maxLevel; i++)
|
||||
{
|
||||
this.head.Next[i] = this.end;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds an item to the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be added.</param>
|
||||
public void Add(T item)
|
||||
{
|
||||
var curNode = this.head;
|
||||
var newLevel = 0;
|
||||
while (this.random.Next(0, 2) > 0 && newLevel < this.maxLevel)
|
||||
{
|
||||
newLevel++;
|
||||
}
|
||||
|
||||
if (newLevel > this.level)
|
||||
{
|
||||
this.level = newLevel;
|
||||
}
|
||||
|
||||
var newNode = new NodeSet<T>(item, newLevel);
|
||||
for (var i = 0; i <= newLevel; i++)
|
||||
{
|
||||
if (i > curNode.Level)
|
||||
public NodeSet(TKey key, int level)
|
||||
{
|
||||
curNode = this.head;
|
||||
this.Key = key;
|
||||
this.Level = level;
|
||||
Next = new NodeSet<TKey>[level + 1];
|
||||
}
|
||||
|
||||
while (curNode.Next[i] != this.end && curNode.Next[i].Key.CompareTo(item) < 0)
|
||||
{
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
|
||||
newNode.Next[i] = curNode.Next[i];
|
||||
curNode.Next[i] = newNode;
|
||||
}
|
||||
|
||||
this.count++;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes provided item from the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be removed.</param>
|
||||
/// <returns>True if removal was successful.</returns>
|
||||
public bool Remove(T item)
|
||||
{
|
||||
var removed = false;
|
||||
var curNode = this.head;
|
||||
for (var i = 0; i <= this.maxLevel; i++)
|
||||
private int count;
|
||||
private readonly Random random;
|
||||
private readonly NodeSet<T> head;
|
||||
private readonly NodeSet<T> end;
|
||||
private readonly int maxLevel = 10;
|
||||
private int level;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Number of elements in the list.
|
||||
/// </summary>
|
||||
public int Count { get => count; }
|
||||
/// <summary>
|
||||
/// Specifies if the collection can be modified.
|
||||
/// </summary>
|
||||
public bool IsReadOnly { get; set; }
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Creates a new instance of SkipList collection.
|
||||
/// </summary>
|
||||
/// <param name="maxLevel">Maximum level of the skip list.</param>
|
||||
public SkipList(int maxLevel = 10)
|
||||
{
|
||||
if (i > curNode.Level)
|
||||
this.maxLevel = maxLevel;
|
||||
random = new Random();
|
||||
head = new NodeSet<T>(default, maxLevel);
|
||||
end = head;
|
||||
for (int i = 0; i <= maxLevel; i++)
|
||||
{
|
||||
curNode = this.head;
|
||||
}
|
||||
|
||||
while (curNode.Next[i] != this.end && curNode.Next[i].Key.CompareTo(item) < 0)
|
||||
{
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
|
||||
if (curNode.Next[i].Key.CompareTo(item) == 0) //Item is present on this level
|
||||
{
|
||||
curNode.Next[i] = curNode.Next[i].Next[i];
|
||||
removed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
head.Next[i] = end;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed)
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds an item to the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be added.</param>
|
||||
public void Add(T item)
|
||||
{
|
||||
this.count--;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the collection.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
for (var i = 0; i < this.maxLevel; i++)
|
||||
{
|
||||
this.head.Next[i] = this.end;
|
||||
}
|
||||
|
||||
this.count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if item is present in the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if item is present in the collection.</returns>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
if (this.Find(item) != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the skip list contents onto the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to hold the values from the list.</param>
|
||||
/// <param name="arrayIndex">Index to start insertion in the array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
var node = this.head.Next[0];
|
||||
while (node != this.end)
|
||||
{
|
||||
array[arrayIndex] = node.Key;
|
||||
arrayIndex++;
|
||||
node = node.Next[0];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the elements from the collection into an array.
|
||||
/// </summary>
|
||||
/// <returns>Array filled with elements from the collection.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
var array = new T[this.count];
|
||||
var index = 0;
|
||||
var curNode = this.head.Next[0];
|
||||
while (curNode != this.end)
|
||||
{
|
||||
array[index] = curNode.Key;
|
||||
index++;
|
||||
curNode = curNode.Next[0];
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
var curNode = this.head.Next[0];
|
||||
while (curNode != this.end)
|
||||
{
|
||||
yield return curNode.Key;
|
||||
curNode = curNode.Next[0];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private NodeSet<T> Find(T key)
|
||||
{
|
||||
var curNode = this.head;
|
||||
|
||||
for (var i = this.level; i >= 0; i--)
|
||||
{
|
||||
while (curNode.Next[i] != this.end)
|
||||
NodeSet<T> curNode = head;
|
||||
int newLevel = 0;
|
||||
while (random.Next(0, 2) > 0 && newLevel < maxLevel)
|
||||
{
|
||||
if (curNode.Next[i].Key.CompareTo(key) > 0)
|
||||
newLevel++;
|
||||
}
|
||||
if (newLevel > level)
|
||||
{
|
||||
level = newLevel;
|
||||
}
|
||||
NodeSet<T> newNode = new NodeSet<T>(item, newLevel);
|
||||
for (var i = 0; i <= newLevel; i++)
|
||||
{
|
||||
if (i > curNode.Level)
|
||||
{
|
||||
curNode = head;
|
||||
}
|
||||
while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0)
|
||||
{
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
newNode.Next[i] = curNode.Next[i];
|
||||
curNode.Next[i] = newNode;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes provided item from the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be removed.</param>
|
||||
/// <returns>True if removal was successful.</returns>
|
||||
public bool Remove(T item)
|
||||
{
|
||||
bool removed = false;
|
||||
NodeSet<T> curNode = head;
|
||||
for (var i = 0; i <= maxLevel; i++)
|
||||
{
|
||||
if (i > curNode.Level)
|
||||
{
|
||||
curNode = head;
|
||||
}
|
||||
while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0)
|
||||
{
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
if (curNode.Next[i].Key.CompareTo(item) == 0) //Item is present on this level
|
||||
{
|
||||
curNode.Next[i] = curNode.Next[i].Next[i];
|
||||
removed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (curNode.Next[i].Key.CompareTo(key) == 0)
|
||||
{
|
||||
return curNode.Next[i];
|
||||
}
|
||||
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
if (removed)
|
||||
{
|
||||
count--;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
curNode = curNode.Next[0];
|
||||
if (curNode != this.end && curNode.Key.CompareTo(key) == 0)
|
||||
/// <summary>
|
||||
/// Clears the collection.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
return curNode;
|
||||
for (int i = 0; i < maxLevel; i++)
|
||||
{
|
||||
head.Next[i] = end;
|
||||
}
|
||||
count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Checks if item is present in the collection.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to be checked.</param>
|
||||
/// <returns>True if item is present in the collection.</returns>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
if (Find(item) != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the skip list contents onto the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to hold the values from the list.</param>
|
||||
/// <param name="arrayIndex">Index to start insertion in the array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
NodeSet<T> node = head.Next[0];
|
||||
while (node != end)
|
||||
{
|
||||
array[arrayIndex] = node.Key;
|
||||
arrayIndex++;
|
||||
node = node.Next[0];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Copies the elements from the collection into an array.
|
||||
/// </summary>
|
||||
/// <returns>Array filled with elements from the collection.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
T[] array = new T[count];
|
||||
int index = 0;
|
||||
NodeSet<T> curNode = head.Next[0];
|
||||
while (curNode != end)
|
||||
{
|
||||
array[index] = curNode.Key;
|
||||
index++;
|
||||
curNode = curNode.Next[0];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the collection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
NodeSet<T> curNode = head.Next[0];
|
||||
while (curNode != end)
|
||||
{
|
||||
yield return curNode.Key;
|
||||
curNode = curNode.Next[0];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private NodeSet<T> Find(T key)
|
||||
{
|
||||
NodeSet<T> curNode = head;
|
||||
|
||||
return default!;
|
||||
for (int i = level; i >= 0; i--)
|
||||
{
|
||||
while (curNode.Next[i] != end)
|
||||
{
|
||||
if (curNode.Next[i].Key.CompareTo(key) > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (curNode.Next[i].Key.CompareTo(key) == 0)
|
||||
{
|
||||
return curNode.Next[i];
|
||||
}
|
||||
curNode = curNode.Next[i];
|
||||
}
|
||||
}
|
||||
|
||||
curNode = curNode.Next[0];
|
||||
if (curNode != end && curNode.Key.CompareTo(key) == 0)
|
||||
{
|
||||
return curNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,287 +1,280 @@
|
||||
namespace System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Treap implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
public sealed class Treap<T> : ICollection<T> where T : IComparable<T>
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
#region Fields
|
||||
/// <summary>
|
||||
/// Treap implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
[Serializable]
|
||||
private class Node<TKey>
|
||||
public sealed class Treap<T> : ICollection<T> where T : IComparable<T>
|
||||
{
|
||||
public TKey Key;
|
||||
public int Priority;
|
||||
public Node<TKey>? Left, Right;
|
||||
public Node(TKey key, int priority)
|
||||
#region Fields
|
||||
[Serializable]
|
||||
private class Node<TKey>
|
||||
{
|
||||
this.Key = key;
|
||||
this.Priority = priority;
|
||||
this.Left = null;
|
||||
this.Right = null;
|
||||
}
|
||||
}
|
||||
private readonly Random randomGen;
|
||||
private Node<T> root = default!;
|
||||
private int count;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Count of values in the treap.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.count;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Not implemented.
|
||||
/// </summary>
|
||||
public bool IsReadOnly => false;
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for treap.
|
||||
/// </summary>
|
||||
public Treap()
|
||||
{
|
||||
this.randomGen = new Random();
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds value to the treap.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
this.root = this.InsertNode(this.root, value);
|
||||
this.count++;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes value from treap.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be removed.</param>
|
||||
public bool Remove(T value)
|
||||
{
|
||||
this.root = this.RemoveNode(this.root, value);
|
||||
this.count--;
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the treap.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
this.Clear(this.root);
|
||||
this.root = default!;
|
||||
this.count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines whether the treap contains the specified value.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to locate in the treap.</param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
return this.Find(this.root, value) != null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the treap structure as an ordered array.
|
||||
/// </summary>
|
||||
/// <returns>Ordered array containing the values stored in the treap.</returns>
|
||||
public T[]? ToArray()
|
||||
{
|
||||
if (this.root != null)
|
||||
{
|
||||
var array = new T[this.count];
|
||||
var index = 0;
|
||||
this.ToArray(this.root, ref array, ref index);
|
||||
return array;
|
||||
}
|
||||
else
|
||||
{
|
||||
return default!;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Copy the treap into the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to be populated with the values contained in the array.</param>
|
||||
/// <param name="arrayIndex">Starting index of the array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
this.ToArray(this.root, ref array, ref arrayIndex);
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the treap. Note that the values are not guaranteed to be sorted.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the treap.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return this.GetEnumerator(this.root);
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
private Node<T> InsertNode(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
node = new Node<T>(key, this.randomGen.Next(0, 100));
|
||||
return node;
|
||||
}
|
||||
else if (key.CompareTo(node.Key) <= 0)
|
||||
{
|
||||
node.Left = this.InsertNode(node.Left!, key);
|
||||
if (node.Left!.Priority > node.Priority)
|
||||
public TKey Key;
|
||||
public int Priority;
|
||||
public Node<TKey> Left, Right;
|
||||
public Node(TKey key, int priority)
|
||||
{
|
||||
node = this.RotateRight(node);
|
||||
Key = key;
|
||||
Priority = priority;
|
||||
Left = null;
|
||||
Right = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
private readonly Random randomGen;
|
||||
private Node<T> root;
|
||||
private int count;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Count of values in the treap.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
node.Right = this.InsertNode(node.Right!, key);
|
||||
if (node.Right!.Priority > node.Priority)
|
||||
get
|
||||
{
|
||||
node = this.RotateLeft(node);
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
private Node<T> RemoveNode(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
/// <summary>
|
||||
/// Not implemented.
|
||||
/// </summary>
|
||||
public bool IsReadOnly => false;
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for treap.
|
||||
/// </summary>
|
||||
public Treap()
|
||||
{
|
||||
return node!;
|
||||
randomGen = new Random();
|
||||
}
|
||||
|
||||
if (key.CompareTo(node.Key) < 0)
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Adds value to the treap.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added.</param>
|
||||
public void Add(T value)
|
||||
{
|
||||
node.Left = this.RemoveNode(node.Left!, key);
|
||||
root = InsertNode(root, value);
|
||||
count++;
|
||||
}
|
||||
else if (key.CompareTo(node.Key) > 0)
|
||||
/// <summary>
|
||||
/// Removes value from treap.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be removed.</param>
|
||||
public bool Remove(T value)
|
||||
{
|
||||
node.Right = this.RemoveNode(node.Right!, key);
|
||||
root = RemoveNode(root, value);
|
||||
count--;
|
||||
return true;
|
||||
}
|
||||
else if (node.Left == null)
|
||||
/// <summary>
|
||||
/// Clears the treap.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
node = node.Right!;
|
||||
Clear(root);
|
||||
root = null;
|
||||
count = 0;
|
||||
}
|
||||
else if (node.Right == null)
|
||||
/// <summary>
|
||||
/// Determines whether the treap contains the specified value.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to locate in the treap.</param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
node = node.Left;
|
||||
return Find(root, value) != null;
|
||||
}
|
||||
else if (node.Left.Priority < node.Right.Priority)
|
||||
/// <summary>
|
||||
/// Returns the treap structure as an ordered array.
|
||||
/// </summary>
|
||||
/// <returns>Ordered array containing the values stored in the treap.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
node = this.RotateLeft(node);
|
||||
node.Left = this.RemoveNode(node.Left!, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = this.RotateRight(node);
|
||||
node.Right = this.RemoveNode(node.Right!, key);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
private Node<T> RotateRight(Node<T> node)
|
||||
{
|
||||
Node<T> temp = node.Left!, temp2 = temp.Right!;
|
||||
temp.Right = node;
|
||||
node.Left = temp2;
|
||||
return temp;
|
||||
}
|
||||
private Node<T> RotateLeft(Node<T> node)
|
||||
{
|
||||
Node<T> temp = node.Right!, temp2 = temp.Left!;
|
||||
temp.Left = node;
|
||||
node.Right = temp2;
|
||||
return temp;
|
||||
}
|
||||
private void Clear(Node<T> node)
|
||||
{
|
||||
if (node.Left != null)
|
||||
{
|
||||
this.Clear(node.Left);
|
||||
}
|
||||
|
||||
if (node.Right != null)
|
||||
{
|
||||
this.Clear(node.Right);
|
||||
}
|
||||
|
||||
node.Left = node.Right = null;
|
||||
}
|
||||
private Node<T> Find(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return node!;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node.Key.CompareTo(key) < 0)
|
||||
if (root != null)
|
||||
{
|
||||
var found = this.Find(node.Left!, key);
|
||||
if (found == null)
|
||||
{
|
||||
found = this.Find(node.Right!, key);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
else if (node.Key.CompareTo(key) > 0)
|
||||
{
|
||||
var found = this.Find(node.Right!, key);
|
||||
if (found == null)
|
||||
{
|
||||
found = this.Find(node.Left!, key);
|
||||
}
|
||||
|
||||
return found;
|
||||
T[] array = new T[count];
|
||||
int index = 0;
|
||||
ToArray(root, ref array, ref index);
|
||||
return array;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Copy the treap into the provided array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to be populated with the values contained in the array.</param>
|
||||
/// <param name="arrayIndex">Starting index of the array.</param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
ToArray(root, ref array, ref arrayIndex);
|
||||
}
|
||||
/// <summary>
|
||||
/// Enumerator that iterates over the treap. Note that the values are not guaranteed to be sorted.
|
||||
/// </summary>
|
||||
/// <returns>Enumerator that iterates over the treap.</returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return GetEnumerator(root);
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
private Node<T> InsertNode(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
node = new Node<T>(key, randomGen.Next(0, 100));
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void ToArray(Node<T> node, ref T[] array, ref int index)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
this.ToArray(node.Left!, ref array, ref index);
|
||||
array[index] = node.Key;
|
||||
index++;
|
||||
this.ToArray(node.Right!, ref array, ref index);
|
||||
}
|
||||
}
|
||||
private IEnumerator<T> GetEnumerator(Node<T> currentNode)
|
||||
{
|
||||
var queue = new Queue<Node<T>>();
|
||||
queue.Enqueue(currentNode);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
currentNode = queue.Dequeue();
|
||||
yield return currentNode.Key;
|
||||
if (currentNode.Left != null)
|
||||
else if (key.CompareTo(node.Key) <= 0)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
node.Left = InsertNode(node.Left, key);
|
||||
if (node.Left.Priority > node.Priority)
|
||||
{
|
||||
node = RotateRight(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentNode.Right != null)
|
||||
else
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
node.Right = InsertNode(node.Right, key);
|
||||
if (node.Right.Priority > node.Priority)
|
||||
{
|
||||
node = RotateLeft(node);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
private Node<T> RemoveNode(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
if (key.CompareTo(node.Key) < 0)
|
||||
{
|
||||
node.Left = RemoveNode(node.Left, key);
|
||||
}
|
||||
else if (key.CompareTo(node.Key) > 0)
|
||||
{
|
||||
node.Right = RemoveNode(node.Right, key);
|
||||
}
|
||||
else if (node.Left == null)
|
||||
{
|
||||
node = node.Right;
|
||||
}
|
||||
else if (node.Right == null)
|
||||
{
|
||||
node = node.Left;
|
||||
}
|
||||
else if (node.Left.Priority < node.Right.Priority)
|
||||
{
|
||||
node = RotateLeft(node);
|
||||
node.Left = RemoveNode(node.Left, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = RotateRight(node);
|
||||
node.Right = RemoveNode(node.Right, key);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
private Node<T> RotateRight(Node<T> node)
|
||||
{
|
||||
Node<T> temp = node.Left, temp2 = temp.Right;
|
||||
temp.Right = node;
|
||||
node.Left = temp2;
|
||||
return temp;
|
||||
}
|
||||
private Node<T> RotateLeft(Node<T> node)
|
||||
{
|
||||
Node<T> temp = node.Right, temp2 = temp.Left;
|
||||
temp.Left = node;
|
||||
node.Right = temp2;
|
||||
return temp;
|
||||
}
|
||||
private void Clear(Node<T> node)
|
||||
{
|
||||
if (node.Left != null)
|
||||
{
|
||||
Clear(node.Left);
|
||||
}
|
||||
if (node.Right != null)
|
||||
{
|
||||
Clear(node.Right);
|
||||
}
|
||||
node.Left = node.Right = null;
|
||||
}
|
||||
private Node<T> Find(Node<T> node, T key)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node.Key.CompareTo(key) < 0)
|
||||
{
|
||||
Node<T> found = Find(node.Left, key);
|
||||
if (found == null)
|
||||
{
|
||||
found = Find(node.Right, key);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
else if (node.Key.CompareTo(key) > 0)
|
||||
{
|
||||
Node<T> found = Find(node.Right, key);
|
||||
if (found == null)
|
||||
{
|
||||
found = Find(node.Left, key);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
else
|
||||
{
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void ToArray(Node<T> node, ref T[] array, ref int index)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
ToArray(node.Left, ref array, ref index);
|
||||
array[index] = node.Key;
|
||||
index++;
|
||||
ToArray(node.Right, ref array, ref index);
|
||||
}
|
||||
}
|
||||
private IEnumerator<T> GetEnumerator(Node<T> currentNode)
|
||||
{
|
||||
Queue<Node<T>> queue = new Queue<Node<T>>();
|
||||
queue.Enqueue(currentNode);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
currentNode = queue.Dequeue();
|
||||
yield return currentNode.Key;
|
||||
if (currentNode.Left != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Left);
|
||||
}
|
||||
if (currentNode.Right != null)
|
||||
{
|
||||
queue.Enqueue(currentNode.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
namespace System.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// https://stackoverflow.com/questions/641361/base32-decoding
|
||||
/// </summary>
|
||||
public static partial class Convert
|
||||
{
|
||||
public static byte[] FromBase32String(string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
throw new ArgumentNullException("input");
|
||||
}
|
||||
|
||||
input = input.TrimEnd('='); //remove padding characters
|
||||
var byteCount = input.Length * 5 / 8; //this must be TRUNCATED
|
||||
var returnArray = new byte[byteCount];
|
||||
|
||||
byte curByte = 0, bitsRemaining = 8;
|
||||
int arrayIndex = 0;
|
||||
|
||||
foreach (var c in input)
|
||||
{
|
||||
var cValue = CharToValue(c);
|
||||
int mask;
|
||||
if (bitsRemaining > 5)
|
||||
{
|
||||
mask = cValue << (bitsRemaining - 5);
|
||||
curByte = (byte)(curByte | mask);
|
||||
bitsRemaining -= 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = cValue >> (5 - bitsRemaining);
|
||||
curByte = (byte)(curByte | mask);
|
||||
returnArray[arrayIndex++] = curByte;
|
||||
curByte = (byte)(cValue << (3 + bitsRemaining));
|
||||
bitsRemaining += 3;
|
||||
}
|
||||
}
|
||||
|
||||
//if we didn't end with a full byte
|
||||
if (arrayIndex != byteCount)
|
||||
{
|
||||
returnArray[arrayIndex] = curByte;
|
||||
}
|
||||
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
public static string ToBase32String(byte[] input)
|
||||
{
|
||||
if (input == null || input.Length == 0)
|
||||
{
|
||||
throw new ArgumentNullException("input");
|
||||
}
|
||||
|
||||
var charCount = (int)Math.Ceiling(input.Length / 5d) * 8;
|
||||
var returnArray = new char[charCount];
|
||||
|
||||
byte nextChar = 0, bitsRemaining = 5;
|
||||
var arrayIndex = 0;
|
||||
|
||||
foreach (var b in input)
|
||||
{
|
||||
nextChar = (byte)(nextChar | (b >> (8 - bitsRemaining)));
|
||||
returnArray[arrayIndex++] = ValueToChar(nextChar);
|
||||
|
||||
if (bitsRemaining < 4)
|
||||
{
|
||||
nextChar = (byte)((b >> (3 - bitsRemaining)) & 31);
|
||||
returnArray[arrayIndex++] = ValueToChar(nextChar);
|
||||
bitsRemaining += 5;
|
||||
}
|
||||
|
||||
bitsRemaining -= 3;
|
||||
nextChar = (byte)((b << bitsRemaining) & 31);
|
||||
}
|
||||
|
||||
//if we didn't end with a full char
|
||||
if (arrayIndex != charCount)
|
||||
{
|
||||
returnArray[arrayIndex++] = ValueToChar(nextChar);
|
||||
while (arrayIndex != charCount) returnArray[arrayIndex++] = '='; //padding
|
||||
}
|
||||
|
||||
return new string(returnArray);
|
||||
}
|
||||
|
||||
private static int CharToValue(char c)
|
||||
{
|
||||
var value = (int)c;
|
||||
|
||||
//65-90 == uppercase letters
|
||||
if (value < 91 && value > 64)
|
||||
{
|
||||
return value - 65;
|
||||
}
|
||||
//50-55 == numbers 2-7
|
||||
if (value < 56 && value > 49)
|
||||
{
|
||||
return value - 24;
|
||||
}
|
||||
//97-122 == lowercase letters
|
||||
if (value < 123 && value > 96)
|
||||
{
|
||||
return value - 97;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Character {c} is not a Base32 character.");
|
||||
}
|
||||
|
||||
private static char ValueToChar(byte b)
|
||||
{
|
||||
if (b < 26)
|
||||
{
|
||||
return (char)(b + 65);
|
||||
}
|
||||
|
||||
if (b < 32)
|
||||
{
|
||||
return (char)(b + 24);
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Byte {b} is not a value Base32 value.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +1,24 @@
|
||||
using System.IO;
|
||||
|
||||
namespace System.Extensions;
|
||||
|
||||
public static class BytesExtensions
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static byte[] ReadAllBytes(this Stream stream)
|
||||
public static class BytesExtensions
|
||||
{
|
||||
if (stream is null)
|
||||
public static byte[] ReadAllBytes(this Stream stream)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(stream));
|
||||
}
|
||||
if (stream is null) throw new ArgumentNullException(nameof(stream));
|
||||
|
||||
var buffer = new byte[256];
|
||||
using var ms = new MemoryStream();
|
||||
int read;
|
||||
while ((read = stream.Read(buffer, 0, 256)) > 0)
|
||||
{
|
||||
ms.Write(buffer, 0, read);
|
||||
}
|
||||
var buffer = new byte[256];
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
int read;
|
||||
while ((read = stream.Read(buffer, 0, 256)) > 0)
|
||||
{
|
||||
ms.Write(buffer, 0, read);
|
||||
}
|
||||
|
||||
return ms.ToArray();
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +1,50 @@
|
||||
namespace System.Extensions;
|
||||
|
||||
public static class CastExtensions
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static int Floor(this double value)
|
||||
public static class CastExtensions
|
||||
{
|
||||
return (int)Math.Floor(value);
|
||||
}
|
||||
public static int Floor(this double value)
|
||||
{
|
||||
return (int)Math.Floor(value);
|
||||
}
|
||||
|
||||
public static int Ceiling(this double value)
|
||||
{
|
||||
return (int)Math.Ceiling(value);
|
||||
}
|
||||
public static int Ceiling(this double value)
|
||||
{
|
||||
return (int)Math.Ceiling(value);
|
||||
}
|
||||
|
||||
public static int Round(this double value)
|
||||
{
|
||||
return (int)Math.Round(value);
|
||||
}
|
||||
public static int Round(this double value)
|
||||
{
|
||||
return (int)Math.Round(value);
|
||||
}
|
||||
|
||||
public static int Floor(this float value)
|
||||
{
|
||||
return (int)Math.Floor(value);
|
||||
}
|
||||
public static int Floor(this float value)
|
||||
{
|
||||
return (int)Math.Floor(value);
|
||||
}
|
||||
|
||||
public static int Ceiling(this float value)
|
||||
{
|
||||
return (int)Math.Ceiling(value);
|
||||
}
|
||||
public static int Ceiling(this float value)
|
||||
{
|
||||
return (int)Math.Ceiling(value);
|
||||
}
|
||||
|
||||
public static int Round(this float value)
|
||||
{
|
||||
return (int)Math.Round(value);
|
||||
}
|
||||
public static int Round(this float value)
|
||||
{
|
||||
return (int)Math.Round(value);
|
||||
}
|
||||
|
||||
public static int ToInt(this double value)
|
||||
{
|
||||
return (int)value;
|
||||
}
|
||||
public static int ToInt(this double value)
|
||||
{
|
||||
return (int)value;
|
||||
}
|
||||
|
||||
public static int ToInt(this float value)
|
||||
{
|
||||
return (int)value;
|
||||
}
|
||||
public static int ToInt(this float value)
|
||||
{
|
||||
return (int)value;
|
||||
}
|
||||
|
||||
public static int ToInt(this decimal value)
|
||||
{
|
||||
return (int)value;
|
||||
public static int ToInt(this decimal value)
|
||||
{
|
||||
return (int)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,88 +1,71 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace System.Extensions;
|
||||
|
||||
public static class LinqExtensions
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static bool None<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
|
||||
public static class LinqExtensions
|
||||
{
|
||||
enumerable.ThrowIfNull(nameof(enumerable));
|
||||
predicate.ThrowIfNull(nameof(predicate));
|
||||
|
||||
return !enumerable.Any(predicate);
|
||||
}
|
||||
|
||||
public static bool None<T>(this IEnumerable<T> enumerable)
|
||||
{
|
||||
enumerable.ThrowIfNull(nameof(enumerable));
|
||||
|
||||
return !enumerable.Any();
|
||||
}
|
||||
|
||||
public static ICollection<T> ClearAnd<T>(this ICollection<T> collection)
|
||||
{
|
||||
if (collection is null)
|
||||
public static bool None<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
enumerable.ThrowIfNull(nameof(enumerable));
|
||||
predicate.ThrowIfNull(nameof(predicate));
|
||||
|
||||
return !enumerable.Any(predicate);
|
||||
}
|
||||
|
||||
collection.Clear();
|
||||
return collection;
|
||||
}
|
||||
|
||||
public static ICollection<T> AddRange<T>(this ICollection<T> collection, IEnumerable<T> values)
|
||||
{
|
||||
if (collection is null)
|
||||
public static bool None<T>(this IEnumerable<T> enumerable)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
enumerable.ThrowIfNull(nameof(enumerable));
|
||||
|
||||
return !enumerable.Any();
|
||||
}
|
||||
|
||||
if (values is null)
|
||||
public static ICollection<T> ClearAnd<T>(this ICollection<T> collection)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(values));
|
||||
if (collection is null) throw new ArgumentNullException(nameof(collection));
|
||||
|
||||
collection.Clear();
|
||||
return collection;
|
||||
}
|
||||
|
||||
foreach (var item in values)
|
||||
|
||||
public static ICollection<T> AddRange<T>(this ICollection<T> collection, IEnumerable<T> values)
|
||||
{
|
||||
collection.Add(item);
|
||||
}
|
||||
if (collection is null) throw new ArgumentNullException(nameof(collection));
|
||||
if (values is null) throw new ArgumentNullException(nameof(values));
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
public static int IndexOfWhere<T>(this ICollection<T> collection, Func<T, bool> selector)
|
||||
{
|
||||
if (collection is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
}
|
||||
|
||||
if (selector is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(selector));
|
||||
}
|
||||
|
||||
var index = 0;
|
||||
foreach (var item in collection)
|
||||
{
|
||||
if (selector(item))
|
||||
foreach(var item in values)
|
||||
{
|
||||
return index;
|
||||
collection.Add(item);
|
||||
}
|
||||
|
||||
index++;
|
||||
return collection;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Do<T>(this IEnumerable<T> enumerable, Action<T> action)
|
||||
{
|
||||
foreach(var value in enumerable)
|
||||
public static int IndexOfWhere<T>(this ICollection<T> collection, Func<T, bool> selector)
|
||||
{
|
||||
action(value);
|
||||
yield return value;
|
||||
if (collection is null) throw new ArgumentNullException(nameof(collection));
|
||||
if (selector is null) throw new ArgumentNullException(nameof(selector));
|
||||
|
||||
var index = 0;
|
||||
foreach (var item in collection)
|
||||
{
|
||||
if (selector(item))
|
||||
{
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Do<T>(this IEnumerable<T> enumerable, Action<T> action)
|
||||
{
|
||||
foreach(var value in enumerable)
|
||||
{
|
||||
action(value);
|
||||
yield return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Logging;
|
||||
|
||||
namespace System.Extensions;
|
||||
|
||||
public static class LoggingExtensions
|
||||
{
|
||||
public static ScopedLogger<T> CreateScopedLogger<T>(this ILogger<T> logger, string methodName, string flowIdentifier)
|
||||
{
|
||||
return ScopedLogger<T>.Create(logger, methodName, flowIdentifier);
|
||||
}
|
||||
|
||||
public static ScopedLogger<T> CreateScopedLogger<T>(this ILogger<T> logger, string methodName)
|
||||
{
|
||||
return ScopedLogger<T>.Create(logger, methodName, string.Empty);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,32 @@
|
||||
namespace System.Extensions;
|
||||
|
||||
public static class ObjectExtensions
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static T Cast<T>(this object obj)
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
return (T)obj;
|
||||
}
|
||||
|
||||
public static T? As<T>(this object obj) where T : class
|
||||
{
|
||||
return obj as T;
|
||||
}
|
||||
|
||||
public static T ThrowIfNull<T>([ValidatedNotNull] this T? obj, string name) where T : class
|
||||
{
|
||||
if (obj is null)
|
||||
public static T Cast<T>(this object obj)
|
||||
{
|
||||
throw new ArgumentNullException(name);
|
||||
return (T)obj;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
public static T As<T>(this object obj) where T : class
|
||||
{
|
||||
return obj as T;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Parameter)]
|
||||
sealed class ValidatedNotNullAttribute : Attribute
|
||||
{
|
||||
public static Optional<T> ToOptional<T>(this T obj)
|
||||
{
|
||||
return Optional.FromValue(obj);
|
||||
}
|
||||
|
||||
public static T ThrowIfNull<T>([ValidatedNotNull] this T obj, string name) where T : class
|
||||
{
|
||||
if (obj is null) throw new ArgumentNullException(name);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Parameter)]
|
||||
sealed class ValidatedNotNullAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class Optional
|
||||
{
|
||||
public static Optional<T> None<T>()
|
||||
{
|
||||
return new Optional<T>.None();
|
||||
}
|
||||
|
||||
public static Optional<T> FromValue<T>(T value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return new Optional<T>.None();
|
||||
}
|
||||
|
||||
return new Optional<T>.Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Optional<T> : IEquatable<Optional<T>>
|
||||
{
|
||||
public Optional(T value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
private T Value { get; }
|
||||
|
||||
public T ExtractValue()
|
||||
{
|
||||
if (this is None)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
public Optional<T> Do(Action<T> onSome, Action onNone)
|
||||
{
|
||||
if (onSome is null) throw new ArgumentNullException(nameof(onSome));
|
||||
if (onNone is null) throw new ArgumentNullException(nameof(onNone));
|
||||
|
||||
if (this is Some)
|
||||
{
|
||||
onSome.Invoke(this.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
onNone.Invoke();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Optional<T> DoAny(Action<T> onSome = null, Action onNone = null)
|
||||
{
|
||||
if (this is Some)
|
||||
{
|
||||
onSome?.Invoke(this.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
onNone?.Invoke();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Optional<V> Switch<V>(Func<T, V> onSome, Func<V> onNone)
|
||||
{
|
||||
if (onSome is null) throw new ArgumentNullException($"{nameof(onSome)}");
|
||||
if (onNone is null) throw new ArgumentNullException($"{nameof(onNone)}");
|
||||
|
||||
if (this is Some)
|
||||
{
|
||||
return Optional.FromValue(onSome.Invoke(this.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Optional.FromValue(onNone.Invoke());
|
||||
}
|
||||
}
|
||||
public Optional<V> SwitchAny<V>(Func<T, V> onSome = null, Func<V> onNone = null)
|
||||
{
|
||||
if (this is Some)
|
||||
{
|
||||
return onSome != null ? Optional.FromValue(onSome.Invoke(this.Value)) : Optional.FromValue(default(V));
|
||||
}
|
||||
else
|
||||
{
|
||||
return onNone != null ? Optional.FromValue(onNone.Invoke()) : Optional.FromValue(default(V));
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Optional<T>)
|
||||
{
|
||||
return this.Equals(obj);
|
||||
}
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
public bool Equals(Optional<T> other)
|
||||
{
|
||||
if (this is Some && other is Some)
|
||||
{
|
||||
return this.As<Some>().Equals(other.As<Some>());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static implicit operator Optional<T>(T value)
|
||||
{
|
||||
return Optional.FromValue(value);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.Value == null ? base.GetHashCode() : this.Value.GetHashCode();
|
||||
}
|
||||
|
||||
internal class Some : Optional<T>, IEquatable<Some>
|
||||
{
|
||||
public Some(T value) : base(value)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Some)
|
||||
{
|
||||
return this.Equals(obj.As<Some>());
|
||||
}
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
public bool Equals(Some other)
|
||||
{
|
||||
if (other is None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (other is Some)
|
||||
{
|
||||
return this.Value.Equals(other.Value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool operator ==(Some left, Some right)
|
||||
{
|
||||
return left?.Equals(right) == true;
|
||||
}
|
||||
|
||||
public static bool operator !=(Some left, Some right)
|
||||
{
|
||||
return left?.Equals(right) != true;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.Value is object ? this.Value.GetHashCode() : this.As<object>().GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
internal class None : Optional<T>
|
||||
{
|
||||
public None() : base(default)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
namespace System.Extensions
|
||||
{
|
||||
public class Result<TSuccess, TFailure>
|
||||
{
|
||||
private readonly object value;
|
||||
|
||||
public Result(TSuccess successValue)
|
||||
{
|
||||
value = successValue;
|
||||
}
|
||||
public Result(TFailure failureValue)
|
||||
{
|
||||
value = failureValue;
|
||||
}
|
||||
|
||||
public bool TryExtractSuccess(out TSuccess successValue)
|
||||
{
|
||||
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
successValue = success;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
successValue = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool TryExtractFailure(out TFailure failureValue)
|
||||
{
|
||||
|
||||
if (value is TFailure failure)
|
||||
{
|
||||
failureValue = failure;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
failureValue = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public Result<TSuccess, TFailure> Do(Action onSuccess, Action onFailure)
|
||||
{
|
||||
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
|
||||
|
||||
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
|
||||
|
||||
if (value is TSuccess)
|
||||
{
|
||||
onSuccess.Invoke();
|
||||
}
|
||||
else if (value is TFailure)
|
||||
{
|
||||
onFailure.Invoke();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Result<TSuccess, TFailure> DoAny(Action onSuccess = null, Action onFailure = null)
|
||||
{
|
||||
if (value is TSuccess)
|
||||
{
|
||||
onSuccess?.Invoke();
|
||||
}
|
||||
else if (value is TFailure)
|
||||
{
|
||||
onFailure?.Invoke();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Result<TSuccess, TFailure> Do(Action<TSuccess> onSuccess, Action<TFailure> onFailure)
|
||||
{
|
||||
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
|
||||
|
||||
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
|
||||
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
onSuccess.Invoke(success);
|
||||
}
|
||||
else if (value is TFailure failure)
|
||||
{
|
||||
onFailure.Invoke(failure);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Result<TSuccess, TFailure> DoAny(Action<TSuccess> onSuccess = null, Action<TFailure> onFailure = null)
|
||||
{
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
onSuccess?.Invoke(success);
|
||||
}
|
||||
else if (value is TFailure failure)
|
||||
{
|
||||
onFailure?.Invoke(failure);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public T Switch<T>(Func<TSuccess, T> onSuccess, Func<TFailure, T> onFailure)
|
||||
{
|
||||
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
|
||||
|
||||
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
|
||||
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
return onSuccess.Invoke(success);
|
||||
}
|
||||
else if (value is TFailure failure)
|
||||
{
|
||||
return onFailure.Invoke(failure);
|
||||
}
|
||||
throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}");
|
||||
}
|
||||
public T SwitchAny<T>(Func<TSuccess, T> onSuccess = null, Func<TFailure, T> onFailure = null)
|
||||
{
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
return onSuccess is null ? default : onSuccess.Invoke(success);
|
||||
}
|
||||
else if (value is TFailure failure)
|
||||
{
|
||||
return onFailure is null ? default : onFailure.Invoke(failure);
|
||||
}
|
||||
throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}");
|
||||
}
|
||||
public Result<V, K> Switch<V, K>(Func<TSuccess, V> onSuccess, Func<TFailure, K> onFailure)
|
||||
{
|
||||
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
|
||||
|
||||
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
|
||||
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
return Result<V, K>.Success(onSuccess.Invoke(success));
|
||||
}
|
||||
else if (value is TFailure failure)
|
||||
{
|
||||
return Result<V, K>.Failure(onFailure.Invoke(failure));
|
||||
}
|
||||
throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}");
|
||||
}
|
||||
public Result<V, K> SwitchAny<V, K>(Func<TSuccess, V> onSuccess, Func<TFailure, K> onFailure)
|
||||
{
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
return Result<V, K>.Success(onSuccess is null ? default : onSuccess.Invoke(success));
|
||||
}
|
||||
else if (value is TFailure failure)
|
||||
{
|
||||
return Result<V, K>.Failure(onFailure is null ? default : onFailure.Invoke(failure));
|
||||
}
|
||||
throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}");
|
||||
}
|
||||
public Optional<TSuccess> ToOptional()
|
||||
{
|
||||
if (value is TSuccess)
|
||||
{
|
||||
return Optional.FromValue(value.Cast<TSuccess>());
|
||||
}
|
||||
|
||||
return Optional.None<TSuccess>();
|
||||
}
|
||||
|
||||
public static implicit operator Result<TSuccess, TFailure>(TSuccess success)
|
||||
{
|
||||
return Success(success);
|
||||
}
|
||||
|
||||
public static implicit operator Result<TSuccess, TFailure>(TFailure failure)
|
||||
{
|
||||
return Failure(failure);
|
||||
}
|
||||
|
||||
public static Result<TSuccess, TFailure> Success(TSuccess value)
|
||||
{
|
||||
return new Result<TSuccess, TFailure>(value);
|
||||
}
|
||||
public static Result<TSuccess, TFailure> Failure(TFailure value)
|
||||
{
|
||||
return new Result<TSuccess, TFailure>(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Extensions;
|
||||
public static class SemaphoreSlimExtensions
|
||||
{
|
||||
public static async Task<SemaphoreSlimContext> Acquire(this SemaphoreSlim semaphore)
|
||||
{
|
||||
return await SemaphoreSlimContext.Create(semaphore);
|
||||
}
|
||||
|
||||
public static async Task<SemaphoreSlimContext> Acquire(this SemaphoreSlim semaphore, CancellationToken cancellationToken)
|
||||
{
|
||||
return await SemaphoreSlimContext.Create(semaphore, cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +1,67 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Extensions;
|
||||
|
||||
public static class StreamExtensions
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static byte[] ReadBytes(this Stream stream, int count)
|
||||
public static class StreamExtensions
|
||||
{
|
||||
if (stream is null)
|
||||
public static void DoWhileReading(this Stream stream, Action<int, byte[]> action, int bufferLength = 256)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(stream));
|
||||
}
|
||||
if (stream is null) throw new ArgumentNullException(nameof(stream));
|
||||
if (action is null) throw new ArgumentNullException(nameof(action));
|
||||
|
||||
var buffer = new byte[count];
|
||||
stream.Read(buffer, 0, count);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static Stream Rewind(this Stream stream)
|
||||
{
|
||||
if (stream is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(stream));
|
||||
}
|
||||
|
||||
if (!stream.CanSeek)
|
||||
{
|
||||
throw new InvalidOperationException("Stream doesn't support rewinding");
|
||||
}
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
|
||||
public static string ReadUntil(this StreamReader sr, string delim)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var found = false;
|
||||
|
||||
while (!found && !sr.EndOfStream)
|
||||
{
|
||||
for (var i = 0; i < delim.Length; i++)
|
||||
var buffer = new byte[bufferLength];
|
||||
var read = stream.Read(buffer, 0, bufferLength);
|
||||
while(read > 0)
|
||||
{
|
||||
var c = (char)sr.Read();
|
||||
sb.Append(c);
|
||||
|
||||
if (c != delim[i])
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == delim.Length - 1)
|
||||
{
|
||||
sb.Remove(sb.Length - delim.Length, delim.Length);
|
||||
found = true;
|
||||
}
|
||||
action(bufferLength, buffer);
|
||||
read = stream.Read(buffer, 0, bufferLength);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
public static byte[] ReadBytes(this Stream stream, int count)
|
||||
{
|
||||
if (stream is null) throw new ArgumentNullException(nameof(stream));
|
||||
|
||||
var buffer = new byte[count];
|
||||
stream.Read(buffer, 0, count);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static Stream Rewind(this Stream stream)
|
||||
{
|
||||
if (stream is null) throw new ArgumentNullException(nameof(stream));
|
||||
|
||||
if (!stream.CanSeek) throw new InvalidOperationException("Stream doesn't support rewinding");
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
|
||||
public static string ReadUntil(this StreamReader sr, string delim)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
bool found = false;
|
||||
|
||||
while (!found && !sr.EndOfStream)
|
||||
{
|
||||
for (int i = 0; i < delim.Length; i++)
|
||||
{
|
||||
char c = (char)sr.Read();
|
||||
sb.Append(c);
|
||||
|
||||
if (c != delim[i])
|
||||
break;
|
||||
|
||||
if (i == delim.Length - 1)
|
||||
{
|
||||
sb.Remove(sb.Length - delim.Length, delim.Length);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
using System.Text;
|
||||
|
||||
namespace System.Extensions;
|
||||
|
||||
public static class StringExtensions
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static bool IsNullOrEmpty(this string s)
|
||||
public static class StringExtensions
|
||||
{
|
||||
return string.IsNullOrEmpty(s);
|
||||
}
|
||||
public static bool IsNullOrEmpty(this string s)
|
||||
{
|
||||
return string.IsNullOrEmpty(s);
|
||||
}
|
||||
|
||||
public static bool IsNullOrWhiteSpace(this string s)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(s);
|
||||
}
|
||||
public static bool IsNullOrWhiteSpace(this string s)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(s);
|
||||
}
|
||||
|
||||
public static byte[] GetBytes(this string s)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(s);
|
||||
}
|
||||
public static byte[] GetBytes(this string s)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(s);
|
||||
}
|
||||
|
||||
public static string GetString(this byte[] bytes)
|
||||
{
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
public static string GetString(this byte[] bytes)
|
||||
{
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class TaskExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Mark task as <see cref="TaskCreationOptions.LongRunning"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Result type.</typeparam>
|
||||
/// <param name="task">Task.</param>
|
||||
/// <returns>The started <see cref="Task{TResult}"/></returns>
|
||||
public static Task<T> LongRunning<T>(this Task<T> task)
|
||||
{
|
||||
return Task.Factory.StartNew(async () =>
|
||||
{
|
||||
return await task;
|
||||
}, TaskCreationOptions.LongRunning).Unwrap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark task as <see cref="TaskCreationOptions.LongRunning"/>.
|
||||
/// </summary>
|
||||
/// <param name="task">Task.</param>
|
||||
/// <returns>The started <see cref="Task"/></returns>
|
||||
public static Task LongRunning(this Task task)
|
||||
{
|
||||
return Task.Factory.StartNew(async () =>
|
||||
{
|
||||
await task;
|
||||
}, TaskCreationOptions.LongRunning).Unwrap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute action periodically and asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="onTick">Action to be executed.</param>
|
||||
/// <param name="dueTime">Time to pass before starting to execute.</param>
|
||||
/// <param name="interval">Interval between procs.</param>
|
||||
/// <param name="token">Cancellation token used to cancel the cycle.</param>
|
||||
/// <returns></returns>
|
||||
public static async Task RunPeriodicAsync(this Action onTick, TimeSpan dueTime, TimeSpan interval, CancellationToken token)
|
||||
{
|
||||
if (dueTime > TimeSpan.Zero)
|
||||
await Task.Delay(dueTime, token).ConfigureAwait(false);
|
||||
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
onTick?.Invoke();
|
||||
if (interval > TimeSpan.Zero)
|
||||
await Task.Delay(interval, token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute's an async Task<T> method which has a void return value synchronously
|
||||
/// </summary>
|
||||
/// <param name="task">Task<T> method to execute</param>
|
||||
public static void RunSync(this Func<Task> task)
|
||||
{
|
||||
var oldContext = SynchronizationContext.Current;
|
||||
var synch = new ExclusiveSynchronizationContext();
|
||||
SynchronizationContext.SetSynchronizationContext(synch);
|
||||
synch.Post(async _ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await task();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
synch.InnerException = e;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
synch.EndMessageLoop();
|
||||
}
|
||||
}, null);
|
||||
synch.BeginMessageLoop();
|
||||
|
||||
SynchronizationContext.SetSynchronizationContext(oldContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute's an async Task<T> method which has a T return type synchronously
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return Type</typeparam>
|
||||
/// <param name="task">Task<T> method to execute</param>
|
||||
/// <returns></returns>
|
||||
public static T RunSync<T>(this Func<Task<T>> task)
|
||||
{
|
||||
var oldContext = SynchronizationContext.Current;
|
||||
var synch = new ExclusiveSynchronizationContext();
|
||||
SynchronizationContext.SetSynchronizationContext(synch);
|
||||
T ret = default(T);
|
||||
synch.Post(async _ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ret = await task();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
synch.InnerException = e;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
synch.EndMessageLoop();
|
||||
}
|
||||
}, null);
|
||||
synch.BeginMessageLoop();
|
||||
SynchronizationContext.SetSynchronizationContext(oldContext);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private class ExclusiveSynchronizationContext : SynchronizationContext
|
||||
{
|
||||
private bool done;
|
||||
public Exception InnerException { get; set; }
|
||||
readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
|
||||
readonly Queue<Tuple<SendOrPostCallback, object>> items =
|
||||
new Queue<Tuple<SendOrPostCallback, object>>();
|
||||
|
||||
public override void Send(SendOrPostCallback d, object state)
|
||||
{
|
||||
throw new NotSupportedException("We cannot send to our same thread");
|
||||
}
|
||||
|
||||
public override void Post(SendOrPostCallback d, object state)
|
||||
{
|
||||
lock (items)
|
||||
{
|
||||
items.Enqueue(Tuple.Create(d, state));
|
||||
}
|
||||
workItemsWaiting.Set();
|
||||
}
|
||||
|
||||
public void EndMessageLoop()
|
||||
{
|
||||
Post(_ => done = true, null);
|
||||
}
|
||||
|
||||
public void BeginMessageLoop()
|
||||
{
|
||||
while (!done)
|
||||
{
|
||||
Tuple<SendOrPostCallback, object> task = null;
|
||||
lock (items)
|
||||
{
|
||||
if (items.Count > 0)
|
||||
{
|
||||
task = items.Dequeue();
|
||||
}
|
||||
}
|
||||
if (task != null)
|
||||
{
|
||||
task.Item1(task.Item2);
|
||||
if (InnerException != null) // the method threw an exeption
|
||||
{
|
||||
throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
workItemsWaiting.WaitOne();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override SynchronizationContext CreateCopy()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace System.Extensions;
|
||||
|
||||
public static class Try
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static Try<TResult> Action<TResult>(Func<TResult> act)
|
||||
public static class Try
|
||||
{
|
||||
return new Try<TResult>(act);
|
||||
}
|
||||
}
|
||||
public class Try<TResult>
|
||||
{
|
||||
private readonly Func<TResult> action;
|
||||
private readonly List<Func<Exception, TResult>> catchActions = new List<Func<Exception, TResult>>();
|
||||
internal Try(Func<TResult> action)
|
||||
{
|
||||
this.action = action;
|
||||
}
|
||||
public static Try<TResult> Action(Func<TResult> act)
|
||||
{
|
||||
return new Try<TResult>(act);
|
||||
}
|
||||
|
||||
public Try<TResult> Catch<TException>(Func<TException, TResult> act) where TException : Exception
|
||||
{
|
||||
this.catchActions.Add((Func<Exception, TResult>)act);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TResult Run()
|
||||
{
|
||||
try
|
||||
public static Try<TResult> Action<TResult>(Func<TResult> act)
|
||||
{
|
||||
return this.action();
|
||||
return new Try<TResult>(act);
|
||||
}
|
||||
catch (Exception ex)
|
||||
}
|
||||
public class Try<TResult>
|
||||
{
|
||||
private readonly Func<TResult> action;
|
||||
private readonly List<Func<Exception, TResult>> catchActions = new List<Func<Exception, TResult>>();
|
||||
internal Try(Func<TResult> action)
|
||||
{
|
||||
foreach (var catchAction in this.catchActions)
|
||||
this.action = action;
|
||||
}
|
||||
public static Try<TResult> Action(Func<TResult> act)
|
||||
{
|
||||
return new Try<TResult>(act);
|
||||
}
|
||||
|
||||
public Try<TResult> Catch<TException>(Func<TException, TResult> act) where TException : Exception
|
||||
{
|
||||
this.catchActions.Add((Func<Exception, TResult>)act);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TResult Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
return catchAction(ex);
|
||||
return action();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public TResult Finally(Action act)
|
||||
{
|
||||
if (act is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(act));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return this.action();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
foreach (var catchAction in this.catchActions)
|
||||
catch (Exception ex)
|
||||
{
|
||||
return catchAction(ex);
|
||||
foreach (var catchAction in this.catchActions)
|
||||
{
|
||||
return catchAction(ex);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
|
||||
public TResult Finally(Action act)
|
||||
{
|
||||
act();
|
||||
if (act is null) throw new ArgumentNullException(nameof(act));
|
||||
|
||||
try
|
||||
{
|
||||
return this.action();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
foreach (var catchAction in this.catchActions)
|
||||
{
|
||||
return catchAction(ex);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
act();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,244 +1,217 @@
|
||||
using System.Extensions;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Net.Http;
|
||||
|
||||
public sealed class HttpClient<Tscope> : IHttpClient<Tscope>, IDisposable
|
||||
namespace System.Http
|
||||
{
|
||||
private readonly bool disposeInnerClient = true;
|
||||
private readonly HttpClient httpClient;
|
||||
private readonly Type scope;
|
||||
private EventHandler<HttpClientEventMessage> eventEmitted;
|
||||
|
||||
public event EventHandler<HttpClientEventMessage> EventEmitted
|
||||
public sealed class HttpClient<Tscope> : IHttpClient<Tscope>, IDisposable
|
||||
{
|
||||
add
|
||||
private readonly HttpClient httpClient;
|
||||
private readonly Type scope;
|
||||
private EventHandler<HttpClientEventMessage> eventEmitted;
|
||||
|
||||
public event EventHandler<HttpClientEventMessage> EventEmitted
|
||||
{
|
||||
this.eventEmitted += value;
|
||||
add
|
||||
{
|
||||
this.eventEmitted += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
this.eventEmitted -= value;
|
||||
}
|
||||
}
|
||||
remove
|
||||
public Uri BaseAddress { get => this.httpClient.BaseAddress; set => this.httpClient.BaseAddress = value; }
|
||||
public HttpRequestHeaders DefaultRequestHeaders => this.httpClient.DefaultRequestHeaders;
|
||||
public long MaxResponseContentBufferSize { get => this.httpClient.MaxResponseContentBufferSize; set => this.httpClient.MaxResponseContentBufferSize = value; }
|
||||
public TimeSpan Timeout { get => this.httpClient.Timeout; set => this.httpClient.Timeout = value; }
|
||||
|
||||
public HttpClient()
|
||||
{
|
||||
#pragma warning disable CS8601 // Possible null reference assignment.
|
||||
this.eventEmitted -= value;
|
||||
#pragma warning restore CS8601 // Possible null reference assignment.
|
||||
this.httpClient = new HttpClient();
|
||||
this.scope = typeof(Tscope);
|
||||
}
|
||||
}
|
||||
public Uri BaseAddress { get => this.httpClient.BaseAddress; set => this.httpClient.BaseAddress = value; }
|
||||
public HttpRequestHeaders DefaultRequestHeaders => this.httpClient.DefaultRequestHeaders;
|
||||
public long MaxResponseContentBufferSize { get => this.httpClient.MaxResponseContentBufferSize; set => this.httpClient.MaxResponseContentBufferSize = value; }
|
||||
public TimeSpan Timeout { get => this.httpClient.Timeout; set => this.httpClient.Timeout = value; }
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
public HttpClient(bool disposeInnerClient = true)
|
||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
{
|
||||
this.disposeInnerClient = disposeInnerClient;
|
||||
this.httpClient = new HttpClient();
|
||||
this.scope = typeof(Tscope);
|
||||
}
|
||||
public HttpClient(
|
||||
HttpMessageHandler handler)
|
||||
{
|
||||
this.httpClient = new HttpClient(handler);
|
||||
this.scope = typeof(Tscope);
|
||||
}
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
public HttpClient(
|
||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
HttpMessageHandler handler,
|
||||
bool disposeInnerClient = true)
|
||||
{
|
||||
this.disposeInnerClient = disposeInnerClient;
|
||||
this.httpClient = new HttpClient(handler);
|
||||
this.scope = typeof(Tscope);
|
||||
}
|
||||
public HttpClient(
|
||||
HttpMessageHandler handler,
|
||||
bool disposeHandler)
|
||||
{
|
||||
this.httpClient = new HttpClient(handler, disposeHandler);
|
||||
this.scope = typeof(Tscope);
|
||||
}
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
public HttpClient(
|
||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
HttpMessageHandler handler,
|
||||
bool disposeHandler,
|
||||
bool disposeInnerClient = true)
|
||||
{
|
||||
this.disposeInnerClient = disposeInnerClient;
|
||||
this.httpClient = new HttpClient(handler, disposeHandler);
|
||||
this.scope = typeof(Tscope);
|
||||
}
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
public HttpClient(
|
||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
HttpClient httpClient,
|
||||
bool disposeInnerClient = true)
|
||||
{
|
||||
this.disposeInnerClient = disposeInnerClient;
|
||||
this.httpClient = httpClient.ThrowIfNull(nameof(httpClient));
|
||||
this.scope = typeof(Tscope);
|
||||
}
|
||||
|
||||
public void CancelPendingRequests()
|
||||
{
|
||||
this.LogDebug(string.Empty, "Canceling request");
|
||||
this.httpClient.CancelPendingRequests();
|
||||
}
|
||||
public Task<HttpResponseMessage> DeleteAsync(string requestUri)
|
||||
{
|
||||
this.LogDebug(requestUri, nameof(DeleteAsync));
|
||||
return this.httpClient.DeleteAsync(requestUri);
|
||||
}
|
||||
public Task<HttpResponseMessage> DeleteAsync(string requestUri, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogDebug(requestUri, nameof(DeleteAsync));
|
||||
return this.httpClient.DeleteAsync(requestUri, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> DeleteAsync(Uri requestUri)
|
||||
{
|
||||
this.LogDebug(requestUri.ToString(), nameof(DeleteAsync));
|
||||
return this.httpClient.DeleteAsync(requestUri);
|
||||
}
|
||||
public Task<HttpResponseMessage> DeleteAsync(Uri requestUri, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogDebug(requestUri.ToString(), nameof(DeleteAsync));
|
||||
return this.httpClient.DeleteAsync(requestUri, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(string requestUri)
|
||||
{
|
||||
this.LogDebug(requestUri, nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption)
|
||||
{
|
||||
this.LogDebug(requestUri, nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri, completionOption);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogDebug(requestUri, nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri, completionOption, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(string requestUri, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogDebug(requestUri, nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(Uri requestUri)
|
||||
{
|
||||
this.LogDebug(requestUri.ToString(), nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption)
|
||||
{
|
||||
this.LogDebug(requestUri.ToString(), nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri, completionOption);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogDebug(requestUri.ToString(), nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri, completionOption, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(Uri requestUri, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogDebug(requestUri.ToString(), nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri, cancellationToken);
|
||||
}
|
||||
public Task<byte[]> GetByteArrayAsync(string requestUri)
|
||||
{
|
||||
this.LogDebug(requestUri, nameof(GetByteArrayAsync));
|
||||
return this.httpClient.GetByteArrayAsync(requestUri);
|
||||
}
|
||||
public Task<byte[]> GetByteArrayAsync(Uri requestUri)
|
||||
{
|
||||
this.LogDebug(requestUri.ToString(), nameof(GetByteArrayAsync));
|
||||
return this.httpClient.GetByteArrayAsync(requestUri);
|
||||
}
|
||||
public Task<Stream> GetStreamAsync(string requestUri)
|
||||
{
|
||||
this.LogDebug(requestUri, nameof(GetStreamAsync));
|
||||
return this.httpClient.GetStreamAsync(requestUri);
|
||||
}
|
||||
public Task<Stream> GetStreamAsync(Uri requestUri)
|
||||
{
|
||||
this.LogDebug(requestUri.ToString(), nameof(GetStreamAsync));
|
||||
return this.httpClient.GetStreamAsync(requestUri);
|
||||
}
|
||||
public Task<string> GetStringAsync(string requestUri)
|
||||
{
|
||||
this.LogDebug(requestUri, nameof(GetStringAsync));
|
||||
return this.httpClient.GetStringAsync(requestUri);
|
||||
}
|
||||
public Task<string> GetStringAsync(Uri requestUri)
|
||||
{
|
||||
this.LogDebug(requestUri.ToString(), nameof(GetStringAsync));
|
||||
return this.httpClient.GetStringAsync(requestUri);
|
||||
}
|
||||
public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)
|
||||
{
|
||||
this.LogDebug(requestUri, nameof(PostAsync));
|
||||
return this.httpClient.PostAsync(requestUri, content);
|
||||
}
|
||||
public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogDebug(requestUri, nameof(PostAsync));
|
||||
return this.httpClient.PostAsync(requestUri, content, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content)
|
||||
{
|
||||
this.LogDebug(requestUri.ToString(), nameof(PostAsync));
|
||||
return this.httpClient.PostAsync(requestUri, content);
|
||||
}
|
||||
public Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogDebug(requestUri.ToString(), nameof(PostAsync));
|
||||
return this.httpClient.PostAsync(requestUri, content, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content)
|
||||
{
|
||||
this.LogDebug(requestUri, nameof(PutAsync));
|
||||
return this.httpClient.PutAsync(requestUri, content);
|
||||
}
|
||||
public Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogDebug(requestUri, nameof(PutAsync));
|
||||
return this.httpClient.PutAsync(requestUri, content, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content)
|
||||
{
|
||||
this.LogDebug(requestUri.ToString(), nameof(PutAsync));
|
||||
return this.httpClient.PutAsync(requestUri, content);
|
||||
}
|
||||
public Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogDebug(requestUri.ToString(), nameof(PutAsync));
|
||||
return this.httpClient.PutAsync(requestUri, content, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
|
||||
{
|
||||
this.LogDebug(request.RequestUri.ToString(), nameof(SendAsync));
|
||||
return this.httpClient.SendAsync(request);
|
||||
}
|
||||
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption)
|
||||
{
|
||||
this.LogDebug(request.RequestUri.ToString(), nameof(SendAsync));
|
||||
return this.httpClient.SendAsync(request, completionOption);
|
||||
}
|
||||
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogDebug(request.RequestUri.ToString(), nameof(SendAsync));
|
||||
return this.httpClient.SendAsync(request, completionOption, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogDebug(request.RequestUri.ToString(), nameof(SendAsync));
|
||||
return this.httpClient.SendAsync(request, cancellationToken);
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.disposeInnerClient)
|
||||
public void CancelPendingRequests()
|
||||
{
|
||||
this.LogInformation(string.Empty, "Canceling request");
|
||||
this.httpClient.CancelPendingRequests();
|
||||
}
|
||||
public Task<HttpResponseMessage> DeleteAsync(string requestUri)
|
||||
{
|
||||
this.LogInformation(requestUri, nameof(DeleteAsync));
|
||||
return this.httpClient.DeleteAsync(requestUri);
|
||||
}
|
||||
public Task<HttpResponseMessage> DeleteAsync(string requestUri, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogInformation(requestUri, nameof(DeleteAsync));
|
||||
return this.httpClient.DeleteAsync(requestUri, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> DeleteAsync(Uri requestUri)
|
||||
{
|
||||
this.LogInformation(requestUri.ToString(), nameof(DeleteAsync));
|
||||
return this.httpClient.DeleteAsync(requestUri);
|
||||
}
|
||||
public Task<HttpResponseMessage> DeleteAsync(Uri requestUri, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogInformation(requestUri.ToString(), nameof(DeleteAsync));
|
||||
return this.httpClient.DeleteAsync(requestUri, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(string requestUri)
|
||||
{
|
||||
this.LogInformation(requestUri, nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption)
|
||||
{
|
||||
this.LogInformation(requestUri, nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri, completionOption);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogInformation(requestUri, nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri, completionOption, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(string requestUri, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogInformation(requestUri, nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(Uri requestUri)
|
||||
{
|
||||
this.LogInformation(requestUri.ToString(), nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption)
|
||||
{
|
||||
this.LogInformation(requestUri.ToString(), nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri, completionOption);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogInformation(requestUri.ToString(), nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri, completionOption, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> GetAsync(Uri requestUri, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogInformation(requestUri.ToString(), nameof(GetAsync));
|
||||
return this.httpClient.GetAsync(requestUri, cancellationToken);
|
||||
}
|
||||
public Task<byte[]> GetByteArrayAsync(string requestUri)
|
||||
{
|
||||
this.LogInformation(requestUri, nameof(GetByteArrayAsync));
|
||||
return this.httpClient.GetByteArrayAsync(requestUri);
|
||||
}
|
||||
public Task<byte[]> GetByteArrayAsync(Uri requestUri)
|
||||
{
|
||||
this.LogInformation(requestUri.ToString(), nameof(GetByteArrayAsync));
|
||||
return this.httpClient.GetByteArrayAsync(requestUri);
|
||||
}
|
||||
public Task<Stream> GetStreamAsync(string requestUri)
|
||||
{
|
||||
this.LogInformation(requestUri, nameof(GetStreamAsync));
|
||||
return this.httpClient.GetStreamAsync(requestUri);
|
||||
}
|
||||
public Task<Stream> GetStreamAsync(Uri requestUri)
|
||||
{
|
||||
this.LogInformation(requestUri.ToString(), nameof(GetStreamAsync));
|
||||
return this.httpClient.GetStreamAsync(requestUri);
|
||||
}
|
||||
public Task<string> GetStringAsync(string requestUri)
|
||||
{
|
||||
this.LogInformation(requestUri, nameof(GetStringAsync));
|
||||
return this.httpClient.GetStringAsync(requestUri);
|
||||
}
|
||||
public Task<string> GetStringAsync(Uri requestUri)
|
||||
{
|
||||
this.LogInformation(requestUri.ToString(), nameof(GetStringAsync));
|
||||
return this.httpClient.GetStringAsync(requestUri);
|
||||
}
|
||||
public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)
|
||||
{
|
||||
this.LogInformation(requestUri, nameof(PostAsync));
|
||||
return this.httpClient.PostAsync(requestUri, content);
|
||||
}
|
||||
public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogInformation(requestUri, nameof(PostAsync));
|
||||
return this.httpClient.PostAsync(requestUri, content, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content)
|
||||
{
|
||||
this.LogInformation(requestUri.ToString(), nameof(PostAsync));
|
||||
return this.httpClient.PostAsync(requestUri, content);
|
||||
}
|
||||
public Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogInformation(requestUri.ToString(), nameof(PostAsync));
|
||||
return this.httpClient.PostAsync(requestUri, content, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content)
|
||||
{
|
||||
this.LogInformation(requestUri, nameof(PutAsync));
|
||||
return this.httpClient.PutAsync(requestUri, content);
|
||||
}
|
||||
public Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogInformation(requestUri, nameof(PutAsync));
|
||||
return this.httpClient.PutAsync(requestUri, content, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content)
|
||||
{
|
||||
this.LogInformation(requestUri.ToString(), nameof(PutAsync));
|
||||
return this.httpClient.PutAsync(requestUri, content);
|
||||
}
|
||||
public Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogInformation(requestUri.ToString(), nameof(PutAsync));
|
||||
return this.httpClient.PutAsync(requestUri, content, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
|
||||
{
|
||||
this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync));
|
||||
return this.httpClient.SendAsync(request);
|
||||
}
|
||||
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption)
|
||||
{
|
||||
this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync));
|
||||
return this.httpClient.SendAsync(request, completionOption);
|
||||
}
|
||||
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync));
|
||||
return this.httpClient.SendAsync(request, completionOption, cancellationToken);
|
||||
}
|
||||
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
this.LogInformation(request.RequestUri.ToString(), nameof(SendAsync));
|
||||
return this.httpClient.SendAsync(request, cancellationToken);
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
this.httpClient.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void LogDebug(string url, string method)
|
||||
{
|
||||
this.eventEmitted?.Invoke(this, new HttpClientEventMessage(this.scope, method, url));
|
||||
private void LogInformation(string url, string method)
|
||||
{
|
||||
this.eventEmitted?.Invoke(this, new HttpClientEventMessage(this.scope, method, url));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
namespace System.Net.Http;
|
||||
|
||||
public sealed class HttpClientEventMessage
|
||||
namespace System.Http
|
||||
{
|
||||
public Type Scope { get; }
|
||||
public string Method { get; }
|
||||
public string Url { get; }
|
||||
|
||||
internal HttpClientEventMessage(Type scope, string method, string url)
|
||||
public sealed class HttpClientEventMessage
|
||||
{
|
||||
this.Scope = scope;
|
||||
this.Method = method;
|
||||
this.Url = url;
|
||||
public Type Scope { get; }
|
||||
public string Method { get; }
|
||||
public string Url { get; }
|
||||
|
||||
internal HttpClientEventMessage(Type scope, string method, string url)
|
||||
{
|
||||
this.Scope = scope;
|
||||
this.Method = method;
|
||||
this.Url = url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +1,49 @@
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Net.Http;
|
||||
|
||||
public interface IHttpClient<TScope>
|
||||
namespace System.Http
|
||||
{
|
||||
event EventHandler<HttpClientEventMessage> EventEmitted;
|
||||
Uri BaseAddress { get; set; }
|
||||
HttpRequestHeaders DefaultRequestHeaders { get; }
|
||||
long MaxResponseContentBufferSize { get; set; }
|
||||
TimeSpan Timeout { get; set; }
|
||||
public interface IHttpClient<TScope>
|
||||
{
|
||||
event EventHandler<HttpClientEventMessage> EventEmitted;
|
||||
Uri BaseAddress { get; set; }
|
||||
HttpRequestHeaders DefaultRequestHeaders { get; }
|
||||
long MaxResponseContentBufferSize { get; set; }
|
||||
TimeSpan Timeout { get; set; }
|
||||
|
||||
void CancelPendingRequests();
|
||||
Task<HttpResponseMessage> DeleteAsync(string requestUri);
|
||||
Task<HttpResponseMessage> DeleteAsync(string requestUri, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> DeleteAsync(Uri requestUri);
|
||||
Task<HttpResponseMessage> DeleteAsync(Uri requestUri, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> GetAsync(string requestUri);
|
||||
Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption);
|
||||
Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> GetAsync(string requestUri, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> GetAsync(Uri requestUri);
|
||||
Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption);
|
||||
Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> GetAsync(Uri requestUri, CancellationToken cancellationToken);
|
||||
Task<byte[]> GetByteArrayAsync(string requestUri);
|
||||
Task<byte[]> GetByteArrayAsync(Uri requestUri);
|
||||
Task<Stream> GetStreamAsync(string requestUri);
|
||||
Task<Stream> GetStreamAsync(Uri requestUri);
|
||||
Task<string> GetStringAsync(string requestUri);
|
||||
Task<string> GetStringAsync(Uri requestUri);
|
||||
Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content);
|
||||
Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content);
|
||||
Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content);
|
||||
Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content);
|
||||
Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request);
|
||||
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption);
|
||||
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
|
||||
void CancelPendingRequests();
|
||||
Task<HttpResponseMessage> DeleteAsync(string requestUri);
|
||||
Task<HttpResponseMessage> DeleteAsync(string requestUri, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> DeleteAsync(Uri requestUri);
|
||||
Task<HttpResponseMessage> DeleteAsync(Uri requestUri, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> GetAsync(string requestUri);
|
||||
Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption);
|
||||
Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> GetAsync(string requestUri, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> GetAsync(Uri requestUri);
|
||||
Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption);
|
||||
Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> GetAsync(Uri requestUri, CancellationToken cancellationToken);
|
||||
Task<byte[]> GetByteArrayAsync(string requestUri);
|
||||
Task<byte[]> GetByteArrayAsync(Uri requestUri);
|
||||
Task<Stream> GetStreamAsync(string requestUri);
|
||||
Task<Stream> GetStreamAsync(Uri requestUri);
|
||||
Task<string> GetStringAsync(string requestUri);
|
||||
Task<string> GetStringAsync(Uri requestUri);
|
||||
Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content);
|
||||
Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content);
|
||||
Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content);
|
||||
Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content);
|
||||
Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request);
|
||||
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption);
|
||||
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken);
|
||||
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Extensions;
|
||||
|
||||
namespace System.Logging;
|
||||
|
||||
public readonly struct ScopedLogger<T>
|
||||
{
|
||||
private readonly ILogger<T> logger;
|
||||
private readonly string scope;
|
||||
private readonly string flowId;
|
||||
|
||||
private ScopedLogger(ILogger<T> logger, string scope, string flowId)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.scope = scope;
|
||||
this.flowId = flowId.IsNullOrWhiteSpace() ? string.Empty : $"[{flowId}] ";
|
||||
}
|
||||
|
||||
public ScopedLogger<T> LogInformation(string message, params object[] parameters)
|
||||
{
|
||||
this.logger.LogInformation(this.CreateMessage(message), parameters);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScopedLogger<T> LogDebug(string message, params object[] parameters)
|
||||
{
|
||||
this.logger.LogDebug(this.CreateMessage(message), parameters);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScopedLogger<T> LogWarning(string message, params object[] parameters)
|
||||
{
|
||||
this.logger.LogWarning(this.CreateMessage(message), parameters);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScopedLogger<T> LogError(string message, params object[] parameters)
|
||||
{
|
||||
this.logger.LogError(this.CreateMessage(message), parameters);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScopedLogger<T> LogCritical(string message, params object[] parameters)
|
||||
{
|
||||
this.logger.LogCritical(this.CreateMessage(message), parameters);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScopedLogger<T> LogWarning(Exception e, string message, params object[] parameters)
|
||||
{
|
||||
this.logger.LogWarning(e, this.CreateMessage(message), parameters);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScopedLogger<T> LogError(Exception e, string message, params object[] parameters)
|
||||
{
|
||||
this.logger.LogError(e, this.CreateMessage(message), parameters);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScopedLogger<T> LogCritical(Exception e, string message, params object[] parameters)
|
||||
{
|
||||
this.logger.LogCritical(e, this.CreateMessage(message), parameters);
|
||||
return this;
|
||||
}
|
||||
|
||||
private string CreateMessage(string message)
|
||||
{
|
||||
return $"{this.flowId}{this.scope}: {message}";
|
||||
}
|
||||
|
||||
public static ScopedLogger<T> Create(ILogger<T> logger, string scope, string flowId)
|
||||
{
|
||||
return new ScopedLogger<T>(logger, scope.ThrowIfNull(nameof(scope)), flowId);
|
||||
}
|
||||
}
|
||||
@@ -1,174 +1,175 @@
|
||||
namespace System.Structures.BitStructures;
|
||||
|
||||
public struct Int32BitStruct : IEquatable<Int32BitStruct>
|
||||
namespace System.Structures.BitStructures
|
||||
{
|
||||
public Int32BitStruct(uint value) => this.Value = value;
|
||||
public Int32BitStruct(int value) { unchecked { this.Value = (uint)value; } }
|
||||
public uint Value { get; set; }
|
||||
public uint Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1U) | (0x1 & value)); }
|
||||
public uint Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1U << 1)) | ((0x1 & value) << 1); }
|
||||
public uint Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1U << 2)) | ((0x1 & value) << 2); }
|
||||
public uint Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1U << 3)) | ((0x1 & value) << 3); }
|
||||
public uint Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1U << 4)) | ((0x1 & value) << 4); }
|
||||
public uint Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1U << 5)) | ((0x1 & value) << 5); }
|
||||
public uint Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1U << 6)) | ((0x1 & value) << 6); }
|
||||
public uint Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1U << 7)) | ((0x1 & value) << 7); }
|
||||
public uint Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1U << 8)) | ((0x1 & value) << 8); }
|
||||
public uint Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1U << 9)) | ((0x1 & value) << 9); }
|
||||
public uint Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1U << 10)) | ((0x1 & value) << 10); }
|
||||
public uint Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1U << 11)) | ((0x1 & value) << 11); }
|
||||
public uint Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1U << 12)) | ((0x1 & value) << 12); }
|
||||
public uint Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1U << 13)) | ((0x1 & value) << 13); }
|
||||
public uint Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1U << 14)) | ((0x1 & value) << 14); }
|
||||
public uint Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1U << 15)) | ((0x1 & value) << 15); }
|
||||
public uint Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1U << 16)) | ((0x1 & value) << 16); }
|
||||
public uint Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1U << 17)) | ((0x1 & value) << 17); }
|
||||
public uint Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1U << 18)) | ((0x1 & value) << 18); }
|
||||
public uint Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1U << 19)) | ((0x1 & value) << 19); }
|
||||
public uint Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1U << 20)) | ((0x1 & value) << 20); }
|
||||
public uint Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1U << 21)) | ((0x1 & value) << 21); }
|
||||
public uint Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1U << 22)) | ((0x1 & value) << 22); }
|
||||
public uint Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1U << 23)) | ((0x1 & value) << 23); }
|
||||
public uint Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1U << 24)) | ((0x1 & value) << 24); }
|
||||
public uint Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1U << 25)) | ((0x1 & value) << 25); }
|
||||
public uint Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1U << 26)) | ((0x1 & value) << 26); }
|
||||
public uint Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1U << 27)) | ((0x1 & value) << 27); }
|
||||
public uint Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1U << 28)) | ((0x1 & value) << 28); }
|
||||
public uint Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1U << 29)) | ((0x1 & value) << 29); }
|
||||
public uint Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1U << 30)) | ((0x1 & value) << 30); }
|
||||
public uint Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1U << 31)) | ((0x1 & value) << 31); }
|
||||
|
||||
public static implicit operator Int32BitStruct(uint value) => new Int32BitStruct(value);
|
||||
public static implicit operator Int32BitStruct(int value) => new Int32BitStruct(value);
|
||||
public static implicit operator int(Int32BitStruct value) => (int)value.Value;
|
||||
public static implicit operator uint(Int32BitStruct value) => value.Value;
|
||||
public static bool operator ==(Int32BitStruct first, Int32BitStruct second)
|
||||
public struct Int32BitStruct : IEquatable<Int32BitStruct>
|
||||
{
|
||||
return first.Value == second.Value;
|
||||
}
|
||||
public Int32BitStruct(uint value) => this.Value = value;
|
||||
public Int32BitStruct(int value) { unchecked { this.Value = (uint)value; } }
|
||||
public uint Value { get; set; }
|
||||
public uint Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1U) | (0x1 & value)); }
|
||||
public uint Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1U << 1)) | ((0x1 & value) << 1); }
|
||||
public uint Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1U << 2)) | ((0x1 & value) << 2); }
|
||||
public uint Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1U << 3)) | ((0x1 & value) << 3); }
|
||||
public uint Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1U << 4)) | ((0x1 & value) << 4); }
|
||||
public uint Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1U << 5)) | ((0x1 & value) << 5); }
|
||||
public uint Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1U << 6)) | ((0x1 & value) << 6); }
|
||||
public uint Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1U << 7)) | ((0x1 & value) << 7); }
|
||||
public uint Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1U << 8)) | ((0x1 & value) << 8); }
|
||||
public uint Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1U << 9)) | ((0x1 & value) << 9); }
|
||||
public uint Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1U << 10)) | ((0x1 & value) << 10); }
|
||||
public uint Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1U << 11)) | ((0x1 & value) << 11); }
|
||||
public uint Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1U << 12)) | ((0x1 & value) << 12); }
|
||||
public uint Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1U << 13)) | ((0x1 & value) << 13); }
|
||||
public uint Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1U << 14)) | ((0x1 & value) << 14); }
|
||||
public uint Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1U << 15)) | ((0x1 & value) << 15); }
|
||||
public uint Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1U << 16)) | ((0x1 & value) << 16); }
|
||||
public uint Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1U << 17)) | ((0x1 & value) << 17); }
|
||||
public uint Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1U << 18)) | ((0x1 & value) << 18); }
|
||||
public uint Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1U << 19)) | ((0x1 & value) << 19); }
|
||||
public uint Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1U << 20)) | ((0x1 & value) << 20); }
|
||||
public uint Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1U << 21)) | ((0x1 & value) << 21); }
|
||||
public uint Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1U << 22)) | ((0x1 & value) << 22); }
|
||||
public uint Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1U << 23)) | ((0x1 & value) << 23); }
|
||||
public uint Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1U << 24)) | ((0x1 & value) << 24); }
|
||||
public uint Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1U << 25)) | ((0x1 & value) << 25); }
|
||||
public uint Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1U << 26)) | ((0x1 & value) << 26); }
|
||||
public uint Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1U << 27)) | ((0x1 & value) << 27); }
|
||||
public uint Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1U << 28)) | ((0x1 & value) << 28); }
|
||||
public uint Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1U << 29)) | ((0x1 & value) << 29); }
|
||||
public uint Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1U << 30)) | ((0x1 & value) << 30); }
|
||||
public uint Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1U << 31)) | ((0x1 & value) << 31); }
|
||||
|
||||
public static bool operator !=(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value != second.Value;
|
||||
}
|
||||
|
||||
public static bool operator ==(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value == second;
|
||||
}
|
||||
|
||||
public static bool operator !=(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value != second;
|
||||
}
|
||||
|
||||
public static bool operator ==(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
public static implicit operator Int32BitStruct(uint value) => new Int32BitStruct(value);
|
||||
public static implicit operator Int32BitStruct(int value) => new Int32BitStruct(value);
|
||||
public static implicit operator int(Int32BitStruct value) => (int)value.Value;
|
||||
public static implicit operator uint(Int32BitStruct value) => value.Value;
|
||||
public static bool operator ==(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value == (uint)second;
|
||||
return first.Value == second.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator !=(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
public static bool operator !=(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value != (uint)second;
|
||||
return first.Value != second.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >=(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value >= second.Value;
|
||||
}
|
||||
|
||||
public static bool operator <=(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value <= second.Value;
|
||||
}
|
||||
|
||||
public static bool operator >=(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
public static bool operator ==(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value >= (uint)second;
|
||||
return first.Value == second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator <=(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
public static bool operator !=(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value <= (uint)second;
|
||||
return first.Value != second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >=(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value >= second;
|
||||
}
|
||||
|
||||
public static bool operator <=(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value <= second;
|
||||
}
|
||||
|
||||
public static bool operator >(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value > second.Value;
|
||||
}
|
||||
|
||||
public static bool operator <(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value < second.Value;
|
||||
}
|
||||
|
||||
public static bool operator >(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
public static bool operator ==(Int32BitStruct first, int second)
|
||||
{
|
||||
return first.Value > (uint)second;
|
||||
unchecked
|
||||
{
|
||||
return first.Value == (uint)second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator <(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
public static bool operator !=(Int32BitStruct first, int second)
|
||||
{
|
||||
return first.Value < (uint)second;
|
||||
unchecked
|
||||
{
|
||||
return first.Value != (uint)second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value > second;
|
||||
}
|
||||
|
||||
public static bool operator <(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value < second;
|
||||
}
|
||||
|
||||
public bool Equals(Int32BitStruct other)
|
||||
{
|
||||
return this.Value == other.Value;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Int32BitStruct)
|
||||
public static bool operator >=(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return this.Equals((Int32BitStruct)obj);
|
||||
return first.Value >= second.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.Equals(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (this.Value).GetHashCode();
|
||||
public static bool operator <=(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value <= second.Value;
|
||||
}
|
||||
|
||||
public static bool operator >=(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value >= (uint)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator <=(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value <= (uint)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >=(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value >= second;
|
||||
}
|
||||
|
||||
public static bool operator <=(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value <= second;
|
||||
}
|
||||
|
||||
public static bool operator >(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value > second.Value;
|
||||
}
|
||||
|
||||
public static bool operator <(Int32BitStruct first, Int32BitStruct second)
|
||||
{
|
||||
return first.Value < second.Value;
|
||||
}
|
||||
|
||||
public static bool operator >(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value > (uint)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator <(Int32BitStruct first, int second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value < (uint)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value > second;
|
||||
}
|
||||
|
||||
public static bool operator <(Int32BitStruct first, uint second)
|
||||
{
|
||||
return first.Value < second;
|
||||
}
|
||||
|
||||
public bool Equals(Int32BitStruct other)
|
||||
{
|
||||
return this.Value == other.Value;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Int32BitStruct)
|
||||
{
|
||||
return this.Equals((Int32BitStruct)obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.Equals(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (this.Value).GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,204 +1,205 @@
|
||||
using System;
|
||||
|
||||
namespace System.Structures.BitStructures;
|
||||
|
||||
public struct Int64BitStruct : IEquatable<Int64BitStruct>
|
||||
namespace System.Structures.BitStructures
|
||||
{
|
||||
public Int64BitStruct(uint low, uint high)
|
||||
public struct Int64BitStruct : IEquatable<Int64BitStruct>
|
||||
{
|
||||
this.Value = low + ((ulong)high << 32);
|
||||
}
|
||||
|
||||
public Int64BitStruct(int low, int high)
|
||||
{
|
||||
unchecked
|
||||
public Int64BitStruct(uint low, uint high)
|
||||
{
|
||||
this.Value = (uint)low + ((ulong)high << 32);
|
||||
this.Value = low + ((ulong)high << 32);
|
||||
}
|
||||
}
|
||||
|
||||
public Int64BitStruct(long value)
|
||||
{
|
||||
unchecked
|
||||
public Int64BitStruct(int low, int high)
|
||||
{
|
||||
this.Value = (ulong)value;
|
||||
unchecked
|
||||
{
|
||||
this.Value = (uint)low + ((ulong)high << 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Int64BitStruct(ulong value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public ulong Value { get; set; }
|
||||
public uint Low { get => (uint)(this.Value & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF)) | (0xFFFFFFFF & value); }
|
||||
public uint High { get => (uint)((this.Value >> 32) & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF00000000)) | ((ulong)(0xFFFFFFFF & value) << 32); }
|
||||
public ulong Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1UL) | (0x1 & value)); }
|
||||
public ulong Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 1)) | ((0x1 & value) << 1); }
|
||||
public ulong Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 2)) | ((0x1 & value) << 2); }
|
||||
public ulong Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 3)) | ((0x1 & value) << 3); }
|
||||
public ulong Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 4)) | ((0x1 & value) << 4); }
|
||||
public ulong Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 5)) | ((0x1 & value) << 5); }
|
||||
public ulong Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 6)) | ((0x1 & value) << 6); }
|
||||
public ulong Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 7)) | ((0x1 & value) << 7); }
|
||||
public ulong Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 8)) | ((0x1 & value) << 8); }
|
||||
public ulong Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 9)) | ((0x1 & value) << 9); }
|
||||
public ulong Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 10)) | ((0x1 & value) << 10); }
|
||||
public ulong Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 11)) | ((0x1 & value) << 11); }
|
||||
public ulong Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 12)) | ((0x1 & value) << 12); }
|
||||
public ulong Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 13)) | ((0x1 & value) << 13); }
|
||||
public ulong Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 14)) | ((0x1 & value) << 14); }
|
||||
public ulong Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 15)) | ((0x1 & value) << 15); }
|
||||
public ulong Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 16)) | ((0x1 & value) << 16); }
|
||||
public ulong Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 17)) | ((0x1 & value) << 17); }
|
||||
public ulong Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 18)) | ((0x1 & value) << 18); }
|
||||
public ulong Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 19)) | ((0x1 & value) << 19); }
|
||||
public ulong Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 20)) | ((0x1 & value) << 20); }
|
||||
public ulong Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 21)) | ((0x1 & value) << 21); }
|
||||
public ulong Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 22)) | ((0x1 & value) << 22); }
|
||||
public ulong Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 23)) | ((0x1 & value) << 23); }
|
||||
public ulong Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 24)) | ((0x1 & value) << 24); }
|
||||
public ulong Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 25)) | ((0x1 & value) << 25); }
|
||||
public ulong Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 26)) | ((0x1 & value) << 26); }
|
||||
public ulong Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 27)) | ((0x1 & value) << 27); }
|
||||
public ulong Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 28)) | ((0x1 & value) << 28); }
|
||||
public ulong Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 29)) | ((0x1 & value) << 29); }
|
||||
public ulong Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 30)) | ((0x1 & value) << 30); }
|
||||
public ulong Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 31)) | ((0x1 & value) << 31); }
|
||||
public ulong Bit32 { get => this.Value >> 32 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 32)) | ((0x1 & value) << 32); }
|
||||
public ulong Bit33 { get => this.Value >> 33 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 33)) | ((0x1 & value) << 33); }
|
||||
public ulong Bit34 { get => this.Value >> 34 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 34)) | ((0x1 & value) << 34); }
|
||||
public ulong Bit35 { get => this.Value >> 35 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 35)) | ((0x1 & value) << 35); }
|
||||
public ulong Bit36 { get => this.Value >> 36 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 36)) | ((0x1 & value) << 36); }
|
||||
public ulong Bit37 { get => this.Value >> 37 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 37)) | ((0x1 & value) << 37); }
|
||||
public ulong Bit38 { get => this.Value >> 38 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 38)) | ((0x1 & value) << 38); }
|
||||
public ulong Bit39 { get => this.Value >> 39 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 39)) | ((0x1 & value) << 39); }
|
||||
public ulong Bit40 { get => this.Value >> 40 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 40)) | ((0x1 & value) << 40); }
|
||||
public ulong Bit41 { get => this.Value >> 41 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 41)) | ((0x1 & value) << 41); }
|
||||
public ulong Bit42 { get => this.Value >> 42 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 42)) | ((0x1 & value) << 42); }
|
||||
public ulong Bit43 { get => this.Value >> 43 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 43)) | ((0x1 & value) << 43); }
|
||||
public ulong Bit44 { get => this.Value >> 44 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 44)) | ((0x1 & value) << 44); }
|
||||
public ulong Bit45 { get => this.Value >> 45 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 45)) | ((0x1 & value) << 45); }
|
||||
public ulong Bit46 { get => this.Value >> 46 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 46)) | ((0x1 & value) << 46); }
|
||||
public ulong Bit47 { get => this.Value >> 47 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 47)) | ((0x1 & value) << 47); }
|
||||
public ulong Bit48 { get => this.Value >> 48 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 48)) | ((0x1 & value) << 48); }
|
||||
public ulong Bit49 { get => this.Value >> 49 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 49)) | ((0x1 & value) << 49); }
|
||||
public ulong Bit50 { get => this.Value >> 50 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 50)) | ((0x1 & value) << 50); }
|
||||
public ulong Bit51 { get => this.Value >> 51 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 51)) | ((0x1 & value) << 51); }
|
||||
public ulong Bit52 { get => this.Value >> 52 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 52)) | ((0x1 & value) << 52); }
|
||||
public ulong Bit53 { get => this.Value >> 53 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 53)) | ((0x1 & value) << 53); }
|
||||
public ulong Bit54 { get => this.Value >> 54 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 54)) | ((0x1 & value) << 54); }
|
||||
public ulong Bit55 { get => this.Value >> 55 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 55)) | ((0x1 & value) << 55); }
|
||||
public ulong Bit56 { get => this.Value >> 56 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 56)) | ((0x1 & value) << 56); }
|
||||
public ulong Bit57 { get => this.Value >> 57 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 57)) | ((0x1 & value) << 57); }
|
||||
public ulong Bit58 { get => this.Value >> 58 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 58)) | ((0x1 & value) << 58); }
|
||||
public ulong Bit59 { get => this.Value >> 59 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 59)) | ((0x1 & value) << 59); }
|
||||
public ulong Bit60 { get => this.Value >> 60 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 60)) | ((0x1 & value) << 60); }
|
||||
public ulong Bit61 { get => this.Value >> 61 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 61)) | ((0x1 & value) << 61); }
|
||||
public ulong Bit62 { get => this.Value >> 62 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 62)) | ((0x1 & value) << 62); }
|
||||
public ulong Bit63 { get => this.Value >> 63 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 63)) | ((0x1 & value) << 63); }
|
||||
|
||||
public static implicit operator Int64BitStruct(ulong value) => new Int64BitStruct(value);
|
||||
public static implicit operator Int64BitStruct(long value) => new Int64BitStruct(value);
|
||||
public static implicit operator long(Int64BitStruct value) => (long)value.Value;
|
||||
public static implicit operator ulong(Int64BitStruct value) => value.Value;
|
||||
public static bool operator ==(Int64BitStruct first, Int64BitStruct second)
|
||||
{
|
||||
return first.Value == second.Value;
|
||||
}
|
||||
|
||||
public static bool operator !=(Int64BitStruct first, Int64BitStruct second)
|
||||
{
|
||||
return first.Value != second.Value;
|
||||
}
|
||||
|
||||
public static bool operator ==(Int64BitStruct first, ulong second)
|
||||
{
|
||||
return first.Value == second;
|
||||
}
|
||||
|
||||
public static bool operator !=(Int64BitStruct first, ulong second)
|
||||
{
|
||||
return first.Value != second;
|
||||
}
|
||||
|
||||
public static bool operator ==(Int64BitStruct first, long second)
|
||||
{
|
||||
unchecked
|
||||
public Int64BitStruct(long value)
|
||||
{
|
||||
return first.Value == (ulong)second;
|
||||
unchecked
|
||||
{
|
||||
this.Value = (ulong)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator !=(Int64BitStruct first, long second)
|
||||
{
|
||||
unchecked
|
||||
public Int64BitStruct(ulong value)
|
||||
{
|
||||
return first.Value != (ulong)second;
|
||||
this.Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >=(Int64BitStruct first, Int64BitStruct second)
|
||||
{
|
||||
return first.Value >= second.Value;
|
||||
}
|
||||
public ulong Value { get; set; }
|
||||
public uint Low { get => (uint)(this.Value & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF)) | (0xFFFFFFFF & value); }
|
||||
public uint High { get => (uint)((this.Value >> 32) & 0xFFFFFFFF); set => this.Value = (this.Value & ~(0xFFFFFFFF00000000)) | ((ulong)(0xFFFFFFFF & value) << 32); }
|
||||
public ulong Bit0 { get => this.Value & 0x1; set => this.Value = (this.Value & ~(0x1UL) | (0x1 & value)); }
|
||||
public ulong Bit1 { get => this.Value >> 1 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 1)) | ((0x1 & value) << 1); }
|
||||
public ulong Bit2 { get => this.Value >> 2 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 2)) | ((0x1 & value) << 2); }
|
||||
public ulong Bit3 { get => this.Value >> 3 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 3)) | ((0x1 & value) << 3); }
|
||||
public ulong Bit4 { get => this.Value >> 4 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 4)) | ((0x1 & value) << 4); }
|
||||
public ulong Bit5 { get => this.Value >> 5 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 5)) | ((0x1 & value) << 5); }
|
||||
public ulong Bit6 { get => this.Value >> 6 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 6)) | ((0x1 & value) << 6); }
|
||||
public ulong Bit7 { get => this.Value >> 7 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 7)) | ((0x1 & value) << 7); }
|
||||
public ulong Bit8 { get => this.Value >> 8 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 8)) | ((0x1 & value) << 8); }
|
||||
public ulong Bit9 { get => this.Value >> 9 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 9)) | ((0x1 & value) << 9); }
|
||||
public ulong Bit10 { get => this.Value >> 10 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 10)) | ((0x1 & value) << 10); }
|
||||
public ulong Bit11 { get => this.Value >> 11 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 11)) | ((0x1 & value) << 11); }
|
||||
public ulong Bit12 { get => this.Value >> 12 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 12)) | ((0x1 & value) << 12); }
|
||||
public ulong Bit13 { get => this.Value >> 13 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 13)) | ((0x1 & value) << 13); }
|
||||
public ulong Bit14 { get => this.Value >> 14 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 14)) | ((0x1 & value) << 14); }
|
||||
public ulong Bit15 { get => this.Value >> 15 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 15)) | ((0x1 & value) << 15); }
|
||||
public ulong Bit16 { get => this.Value >> 16 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 16)) | ((0x1 & value) << 16); }
|
||||
public ulong Bit17 { get => this.Value >> 17 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 17)) | ((0x1 & value) << 17); }
|
||||
public ulong Bit18 { get => this.Value >> 18 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 18)) | ((0x1 & value) << 18); }
|
||||
public ulong Bit19 { get => this.Value >> 19 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 19)) | ((0x1 & value) << 19); }
|
||||
public ulong Bit20 { get => this.Value >> 20 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 20)) | ((0x1 & value) << 20); }
|
||||
public ulong Bit21 { get => this.Value >> 21 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 21)) | ((0x1 & value) << 21); }
|
||||
public ulong Bit22 { get => this.Value >> 22 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 22)) | ((0x1 & value) << 22); }
|
||||
public ulong Bit23 { get => this.Value >> 23 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 23)) | ((0x1 & value) << 23); }
|
||||
public ulong Bit24 { get => this.Value >> 24 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 24)) | ((0x1 & value) << 24); }
|
||||
public ulong Bit25 { get => this.Value >> 25 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 25)) | ((0x1 & value) << 25); }
|
||||
public ulong Bit26 { get => this.Value >> 26 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 26)) | ((0x1 & value) << 26); }
|
||||
public ulong Bit27 { get => this.Value >> 27 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 27)) | ((0x1 & value) << 27); }
|
||||
public ulong Bit28 { get => this.Value >> 28 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 28)) | ((0x1 & value) << 28); }
|
||||
public ulong Bit29 { get => this.Value >> 29 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 29)) | ((0x1 & value) << 29); }
|
||||
public ulong Bit30 { get => this.Value >> 30 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 30)) | ((0x1 & value) << 30); }
|
||||
public ulong Bit31 { get => this.Value >> 31 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 31)) | ((0x1 & value) << 31); }
|
||||
public ulong Bit32 { get => this.Value >> 32 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 32)) | ((0x1 & value) << 32); }
|
||||
public ulong Bit33 { get => this.Value >> 33 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 33)) | ((0x1 & value) << 33); }
|
||||
public ulong Bit34 { get => this.Value >> 34 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 34)) | ((0x1 & value) << 34); }
|
||||
public ulong Bit35 { get => this.Value >> 35 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 35)) | ((0x1 & value) << 35); }
|
||||
public ulong Bit36 { get => this.Value >> 36 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 36)) | ((0x1 & value) << 36); }
|
||||
public ulong Bit37 { get => this.Value >> 37 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 37)) | ((0x1 & value) << 37); }
|
||||
public ulong Bit38 { get => this.Value >> 38 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 38)) | ((0x1 & value) << 38); }
|
||||
public ulong Bit39 { get => this.Value >> 39 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 39)) | ((0x1 & value) << 39); }
|
||||
public ulong Bit40 { get => this.Value >> 40 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 40)) | ((0x1 & value) << 40); }
|
||||
public ulong Bit41 { get => this.Value >> 41 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 41)) | ((0x1 & value) << 41); }
|
||||
public ulong Bit42 { get => this.Value >> 42 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 42)) | ((0x1 & value) << 42); }
|
||||
public ulong Bit43 { get => this.Value >> 43 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 43)) | ((0x1 & value) << 43); }
|
||||
public ulong Bit44 { get => this.Value >> 44 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 44)) | ((0x1 & value) << 44); }
|
||||
public ulong Bit45 { get => this.Value >> 45 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 45)) | ((0x1 & value) << 45); }
|
||||
public ulong Bit46 { get => this.Value >> 46 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 46)) | ((0x1 & value) << 46); }
|
||||
public ulong Bit47 { get => this.Value >> 47 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 47)) | ((0x1 & value) << 47); }
|
||||
public ulong Bit48 { get => this.Value >> 48 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 48)) | ((0x1 & value) << 48); }
|
||||
public ulong Bit49 { get => this.Value >> 49 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 49)) | ((0x1 & value) << 49); }
|
||||
public ulong Bit50 { get => this.Value >> 50 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 50)) | ((0x1 & value) << 50); }
|
||||
public ulong Bit51 { get => this.Value >> 51 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 51)) | ((0x1 & value) << 51); }
|
||||
public ulong Bit52 { get => this.Value >> 52 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 52)) | ((0x1 & value) << 52); }
|
||||
public ulong Bit53 { get => this.Value >> 53 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 53)) | ((0x1 & value) << 53); }
|
||||
public ulong Bit54 { get => this.Value >> 54 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 54)) | ((0x1 & value) << 54); }
|
||||
public ulong Bit55 { get => this.Value >> 55 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 55)) | ((0x1 & value) << 55); }
|
||||
public ulong Bit56 { get => this.Value >> 56 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 56)) | ((0x1 & value) << 56); }
|
||||
public ulong Bit57 { get => this.Value >> 57 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 57)) | ((0x1 & value) << 57); }
|
||||
public ulong Bit58 { get => this.Value >> 58 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 58)) | ((0x1 & value) << 58); }
|
||||
public ulong Bit59 { get => this.Value >> 59 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 59)) | ((0x1 & value) << 59); }
|
||||
public ulong Bit60 { get => this.Value >> 60 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 60)) | ((0x1 & value) << 60); }
|
||||
public ulong Bit61 { get => this.Value >> 61 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 61)) | ((0x1 & value) << 61); }
|
||||
public ulong Bit62 { get => this.Value >> 62 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 62)) | ((0x1 & value) << 62); }
|
||||
public ulong Bit63 { get => this.Value >> 63 & 0x1; set => this.Value = (this.Value & ~(0x1UL << 63)) | ((0x1 & value) << 63); }
|
||||
|
||||
public static bool operator <=(Int64BitStruct first, Int64BitStruct second)
|
||||
{
|
||||
return first.Value <= second.Value;
|
||||
}
|
||||
|
||||
public static bool operator >=(Int64BitStruct first, long second)
|
||||
{
|
||||
unchecked
|
||||
public static implicit operator Int64BitStruct(ulong value) => new Int64BitStruct(value);
|
||||
public static implicit operator Int64BitStruct(long value) => new Int64BitStruct(value);
|
||||
public static implicit operator long(Int64BitStruct value) => (long)value.Value;
|
||||
public static implicit operator ulong(Int64BitStruct value) => value.Value;
|
||||
public static bool operator ==(Int64BitStruct first, Int64BitStruct second)
|
||||
{
|
||||
return first.Value >= (ulong)second;
|
||||
return first.Value == second.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator <=(Int64BitStruct first, long second)
|
||||
{
|
||||
unchecked
|
||||
public static bool operator !=(Int64BitStruct first, Int64BitStruct second)
|
||||
{
|
||||
return first.Value <= (ulong)second;
|
||||
return first.Value != second.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >=(Int64BitStruct first, ulong second)
|
||||
{
|
||||
unchecked
|
||||
public static bool operator ==(Int64BitStruct first, ulong second)
|
||||
{
|
||||
return first.Value >= second;
|
||||
return first.Value == second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator <=(Int64BitStruct first, ulong second)
|
||||
{
|
||||
unchecked
|
||||
public static bool operator !=(Int64BitStruct first, ulong second)
|
||||
{
|
||||
return first.Value <= second;
|
||||
return first.Value != second;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(Int64BitStruct other)
|
||||
{
|
||||
return this.Value == other.Value;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Int64BitStruct)
|
||||
public static bool operator ==(Int64BitStruct first, long second)
|
||||
{
|
||||
return this.Equals((Int64BitStruct)obj);
|
||||
unchecked
|
||||
{
|
||||
return first.Value == (ulong)second;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.Equals(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.Value.GetHashCode();
|
||||
public static bool operator !=(Int64BitStruct first, long second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value != (ulong)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >=(Int64BitStruct first, Int64BitStruct second)
|
||||
{
|
||||
return first.Value >= second.Value;
|
||||
}
|
||||
|
||||
public static bool operator <=(Int64BitStruct first, Int64BitStruct second)
|
||||
{
|
||||
return first.Value <= second.Value;
|
||||
}
|
||||
|
||||
public static bool operator >=(Int64BitStruct first, long second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value >= (ulong)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator <=(Int64BitStruct first, long second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value <= (ulong)second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator >=(Int64BitStruct first, ulong second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value >= second;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator <=(Int64BitStruct first, ulong second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return first.Value <= second;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(Int64BitStruct other)
|
||||
{
|
||||
return this.Value == other.Value;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Int64BitStruct)
|
||||
{
|
||||
return this.Equals((Int64BitStruct)obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.Equals(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.Value.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,13 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<RootNamespace>System</RootNamespace>
|
||||
<Version>1.9</Version>
|
||||
<Version>1.3.0</Version>
|
||||
<Authors>Alexandru Macocian</Authors>
|
||||
<RepositoryUrl>https://github.com/AlexMacocian/SystemExtensions</RepositoryUrl>
|
||||
<Description>Extensions for the System namespace</Description>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -19,12 +16,6 @@
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="System.Text.Json" Version="10.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System;
|
||||
|
||||
/// <summary>
|
||||
/// Async implementation of <see cref="Lazy{T}"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Credits: https://devblogs.microsoft.com/pfxteam/asynclazyt/
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">Type of value to be returned.</typeparam>
|
||||
public sealed class AsyncLazy<T> : Lazy<Task<T>>
|
||||
{
|
||||
public TaskAwaiter<T> GetAwaiter() => this.Value.GetAwaiter();
|
||||
|
||||
public AsyncLazy(Func<T> valueFactory)
|
||||
: base(() => Task.Factory.StartNew(valueFactory))
|
||||
{
|
||||
}
|
||||
|
||||
public AsyncLazy(Func<Task<T>> taskFactory)
|
||||
: base(() => Task.Factory.StartNew(() => taskFactory()).Unwrap())
|
||||
{
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,30 +0,0 @@
|
||||
using System.Extensions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Threading;
|
||||
public readonly struct SemaphoreSlimContext : IDisposable
|
||||
{
|
||||
private readonly SemaphoreSlim semaphore;
|
||||
|
||||
private SemaphoreSlimContext(SemaphoreSlim semaphoreSlim)
|
||||
{
|
||||
this.semaphore = semaphoreSlim.ThrowIfNull(nameof(semaphoreSlim));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.semaphore.Release();
|
||||
}
|
||||
|
||||
public static async Task<SemaphoreSlimContext> Create(SemaphoreSlim semaphore)
|
||||
{
|
||||
await semaphore.ThrowIfNull(nameof(semaphore)).WaitAsync();
|
||||
return new SemaphoreSlimContext(semaphore);
|
||||
}
|
||||
|
||||
public static async Task<SemaphoreSlimContext> Create(SemaphoreSlim semaphore, CancellationToken cancellationToken)
|
||||
{
|
||||
await semaphore.ThrowIfNull(nameof(semaphore)).WaitAsync(cancellationToken);
|
||||
return new SemaphoreSlimContext(semaphore);
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Extensions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Net.WebSockets;
|
||||
|
||||
// TODO: Cannot properly test because ClientWebSocket is sealed
|
||||
public sealed class ClientWebSocket<TScope> : IClientWebSocket<TScope>, IDisposable
|
||||
{
|
||||
private readonly ILogger<TScope>? logger;
|
||||
private ClientWebSocket internalWebSocket = new();
|
||||
|
||||
public ClientWebSocketOptions Options => this.internalWebSocket.Options;
|
||||
|
||||
public WebSocketCloseStatus? CloseStatus => this.internalWebSocket.CloseStatus;
|
||||
|
||||
public string CloseStatusDescription => this.internalWebSocket.CloseStatusDescription;
|
||||
|
||||
public string SubProtocol => this.internalWebSocket.SubProtocol;
|
||||
|
||||
public WebSocketState State => this.internalWebSocket.State;
|
||||
|
||||
public ClientWebSocket()
|
||||
{
|
||||
}
|
||||
|
||||
public ClientWebSocket(ILogger<TScope> logger)
|
||||
{
|
||||
this.logger = logger.ThrowIfNull(nameof(logger));
|
||||
}
|
||||
|
||||
public ClientWebSocket(ClientWebSocket clientWebSocket, ILogger<TScope> logger)
|
||||
{
|
||||
this.internalWebSocket = clientWebSocket.ThrowIfNull(nameof(clientWebSocket));
|
||||
this.logger = logger.ThrowIfNull(nameof(logger));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
var scopedLogger = this.logger?.CreateScopedLogger(nameof(Dispose), string.Empty);
|
||||
scopedLogger?.LogDebug($"Disposing websocket");
|
||||
this.internalWebSocket?.Dispose();
|
||||
}
|
||||
|
||||
public void Abort()
|
||||
{
|
||||
var scopedLogger = this.logger?.CreateScopedLogger(nameof(Abort), string.Empty);
|
||||
scopedLogger?.LogDebug($"Aborting websocket");
|
||||
this.internalWebSocket.Abort();
|
||||
}
|
||||
|
||||
public Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken)
|
||||
{
|
||||
var scopedLogger = this.logger?.CreateScopedLogger(nameof(CloseAsync), string.Empty);
|
||||
scopedLogger?.LogDebug($"Closing websocket. Status [{closeStatus}]. Status Description [{statusDescription}]");
|
||||
return this.internalWebSocket.CloseAsync(closeStatus, statusDescription, cancellationToken);
|
||||
}
|
||||
|
||||
public Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken)
|
||||
{
|
||||
var scopedLogger = this.logger?.CreateScopedLogger(nameof(CloseOutputAsync), string.Empty);
|
||||
scopedLogger?.LogDebug($"Closing output. Status [{closeStatus}]. Status Description [{statusDescription}]");
|
||||
return this.internalWebSocket.CloseOutputAsync(closeStatus, statusDescription, cancellationToken);
|
||||
}
|
||||
|
||||
public Task ConnectAsync(Uri uri, CancellationToken cancellationToken)
|
||||
{
|
||||
var scopedLogger = this.logger?.CreateScopedLogger(nameof(ConnectAsync), string.Empty);
|
||||
scopedLogger?.LogDebug($"Connecting to {uri}");
|
||||
return this.internalWebSocket.ConnectAsync(uri, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer, CancellationToken cancellationToken)
|
||||
{
|
||||
var scopedLogger = this.logger?.CreateScopedLogger(nameof(ConnectAsync), string.Empty);
|
||||
scopedLogger?.LogDebug($"Attempting to receive bytes");
|
||||
var result = await this.internalWebSocket.ReceiveAsync(buffer, cancellationToken);
|
||||
scopedLogger?.LogDebug($"Received message [{result.MessageType}]");
|
||||
scopedLogger?.LogDebug($"Type: {result.MessageType}\nCount: {result.Count}\nEndOfMessage: {result.EndOfMessage}\nCloseStatus: {result.CloseStatus}\nCloseStatusDescription: {result.CloseStatusDescription}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Task SendAsync(ArraySegment<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)
|
||||
{
|
||||
var scopedLogger = this.logger?.CreateScopedLogger(nameof(SendAsync), string.Empty);
|
||||
scopedLogger?.LogDebug($"Sending bytes");
|
||||
scopedLogger?.LogDebug($"Type: {messageType}\nCount: {buffer.Count}\nEndOfMessage: {endOfMessage}");
|
||||
return this.internalWebSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken);
|
||||
}
|
||||
|
||||
public void RefreshSocket(ClientWebSocket? clientWebSocket = null)
|
||||
{
|
||||
this.internalWebSocket?.Dispose();
|
||||
this.internalWebSocket = clientWebSocket ?? new ClientWebSocket();
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Net.WebSockets;
|
||||
|
||||
public interface IClientWebSocket<TScope>
|
||||
{
|
||||
WebSocketCloseStatus? CloseStatus { get; }
|
||||
|
||||
string CloseStatusDescription { get; }
|
||||
|
||||
ClientWebSocketOptions Options { get; }
|
||||
|
||||
WebSocketState State { get; }
|
||||
|
||||
string SubProtocol { get; }
|
||||
|
||||
void Abort();
|
||||
|
||||
Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken);
|
||||
|
||||
Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken);
|
||||
|
||||
Task ConnectAsync(Uri uri, CancellationToken cancellationToken);
|
||||
|
||||
void Dispose();
|
||||
|
||||
Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer, CancellationToken cancellationToken);
|
||||
|
||||
Task SendAsync(ArraySegment<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken);
|
||||
|
||||
void RefreshSocket(ClientWebSocket? clientWebSocket = default);
|
||||
}
|
||||
@@ -3,125 +3,153 @@ using System.Collections.Generic;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.IO;
|
||||
|
||||
namespace System.Collections.Tests;
|
||||
|
||||
[TestClass()]
|
||||
public class AVLTreeTests
|
||||
namespace System.Collections.Tests
|
||||
{
|
||||
private AVLTree<int> avlTree = new AVLTree<int>();
|
||||
[TestMethod()]
|
||||
public void AVLTreeTest()
|
||||
[TestClass()]
|
||||
public class AVLTreeTests
|
||||
{
|
||||
this.avlTree = new AVLTree<int>();
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void AddTest()
|
||||
{
|
||||
try
|
||||
private AVLTree<int> avlTree = new AVLTree<int>();
|
||||
[TestMethod()]
|
||||
public void AVLTreeTest()
|
||||
{
|
||||
for (var i = 0; i < 100; i++)
|
||||
avlTree = new AVLTree<int>();
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void AddTest()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.avlTree.Add(i * 20 - (50 + i));
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i * 20 - (50 + i));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Assert.Fail(e.Message + "\n" + e.StackTrace);
|
||||
}
|
||||
if (avlTree.Count != 100)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
[TestMethod()]
|
||||
public void ContainsTest()
|
||||
{
|
||||
Assert.Fail(e.Message + "\n" + e.StackTrace);
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
|
||||
if (!avlTree.Contains(50))
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.avlTree.Count != 100)
|
||||
[TestMethod()]
|
||||
public void RemoveTest()
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ContainsTest()
|
||||
{
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
this.avlTree.Add(i);
|
||||
avlTree.Remove(50);
|
||||
|
||||
if (avlTree.Contains(50))
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.avlTree.Contains(50))
|
||||
[TestMethod()]
|
||||
public void ClearTest()
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void RemoveTest()
|
||||
{
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
this.avlTree.Add(i);
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
avlTree.Clear();
|
||||
if(avlTree.Count > 0)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
this.avlTree.Remove(50);
|
||||
|
||||
if (this.avlTree.Contains(50))
|
||||
[TestMethod()]
|
||||
public void CopyToTest()
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ClearTest()
|
||||
{
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
this.avlTree.Add(i);
|
||||
int[] array = new int[100];
|
||||
avlTree.CopyTo(array, 0);
|
||||
}
|
||||
|
||||
this.avlTree.Clear();
|
||||
if(this.avlTree.Count > 0)
|
||||
[TestMethod()]
|
||||
public void GetEnumeratorTest()
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
int count = 0;
|
||||
foreach(int value in avlTree)
|
||||
{
|
||||
count++;
|
||||
System.Diagnostics.Debug.WriteLine(value);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void CopyToTest()
|
||||
{
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
this.avlTree.Add(i);
|
||||
if(count != avlTree.Count)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
var array = new int[100];
|
||||
this.avlTree.CopyTo(array, 0);
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void GetEnumeratorTest()
|
||||
{
|
||||
for (var i = 0; i < 100; i++)
|
||||
[TestMethod()]
|
||||
public void ToArrayTest()
|
||||
{
|
||||
this.avlTree.Add(i);
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
|
||||
int[] array = avlTree.ToArray();
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
foreach(var value in this.avlTree)
|
||||
[TestMethod()]
|
||||
public void Serialize()
|
||||
{
|
||||
count++;
|
||||
System.Diagnostics.Debug.WriteLine(value);
|
||||
AVLTree<int> avlTree2 = new AVLTree<int>();
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
avlTree.Add(i);
|
||||
}
|
||||
BinaryFormatter serializer = new BinaryFormatter();
|
||||
string s = string.Empty;
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
serializer.Serialize(stream, avlTree);
|
||||
stream.Position = 0;
|
||||
avlTree2 = (AVLTree<int>)serializer.Deserialize(stream);
|
||||
}
|
||||
IEnumerator<int> avlTreeEnum = avlTree.GetEnumerator();
|
||||
IEnumerator<int> avlTree2Enum = avlTree2.GetEnumerator();
|
||||
|
||||
for(int i = 0; i < 100; i++)
|
||||
{
|
||||
if(avlTreeEnum.Current != avlTree2Enum.Current)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
avlTreeEnum.MoveNext();
|
||||
avlTree2Enum.MoveNext();
|
||||
}
|
||||
}
|
||||
|
||||
if(count != this.avlTree.Count)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ToArrayTest()
|
||||
{
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
this.avlTree.Add(i);
|
||||
}
|
||||
|
||||
_ = this.avlTree.ToArray();
|
||||
}
|
||||
}
|
||||
@@ -3,180 +3,200 @@ using System.Collections.Generic;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.IO;
|
||||
|
||||
namespace System.Collections.Tests;
|
||||
|
||||
[TestClass()]
|
||||
public class BinaryHeapTests
|
||||
namespace System.Collections.Tests
|
||||
{
|
||||
private BinaryHeap<int> binaryHeap = new BinaryHeap<int>();
|
||||
[TestMethod()]
|
||||
public void BinaryHeapTest()
|
||||
[TestClass()]
|
||||
public class BinaryHeapTests
|
||||
{
|
||||
this.binaryHeap = new BinaryHeap<int>();
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void BinaryHeapTest1()
|
||||
{
|
||||
this.binaryHeap = new BinaryHeap<int>(100);
|
||||
if (this.binaryHeap.Count != 0 && this.binaryHeap.Capacity != 100)
|
||||
private BinaryHeap<int> binaryHeap = new BinaryHeap<int>();
|
||||
[TestMethod()]
|
||||
public void BinaryHeapTest()
|
||||
{
|
||||
Assert.Fail();
|
||||
binaryHeap = new BinaryHeap<int>();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
[Timeout(500)]
|
||||
public void InsertTest()
|
||||
{
|
||||
try
|
||||
[TestMethod()]
|
||||
public void BinaryHeapTest1()
|
||||
{
|
||||
for (var i = 0; i < 100; i++)
|
||||
binaryHeap = new BinaryHeap<int>(100);
|
||||
if (binaryHeap.Count != 0 && binaryHeap.Capacity != 100)
|
||||
{
|
||||
this.binaryHeap.Add(i * 20 - (50 + i));
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
[TestMethod()]
|
||||
[Timeout(500)]
|
||||
public void InsertTest()
|
||||
{
|
||||
Assert.Fail(e.Message + "\n" + e.StackTrace);
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
binaryHeap.Add(i * 20 - (50 + i));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Assert.Fail(e.Message + "\n" + e.StackTrace);
|
||||
}
|
||||
if (binaryHeap.Count != 100)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.binaryHeap.Count != 100)
|
||||
[TestMethod()]
|
||||
[Timeout(500)]
|
||||
public void DeleteMinTest()
|
||||
{
|
||||
try
|
||||
{
|
||||
int tries = binaryHeap.Count;
|
||||
while (binaryHeap.Count > 0)
|
||||
{
|
||||
if (tries == 0)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
System.Diagnostics.Debug.WriteLine(binaryHeap.Remove());
|
||||
tries--;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Assert.Fail(e.Message + "\n" + e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void MinMaxTest()
|
||||
{
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
binaryHeap.Add(i);
|
||||
}
|
||||
if (binaryHeap.Min != 0 || binaryHeap.Max != 999)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ClearTest()
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
binaryHeap.Add(i);
|
||||
}
|
||||
binaryHeap.Clear();
|
||||
if (binaryHeap.Count > 0 || binaryHeap.Capacity != 160)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ClearTest2()
|
||||
{
|
||||
for (int i = 100; i < 200; i++)
|
||||
{
|
||||
binaryHeap.Add(i);
|
||||
}
|
||||
binaryHeap.Clear(false);
|
||||
int[] array = binaryHeap.ToArray();
|
||||
if (binaryHeap.Count > 0 || binaryHeap.Capacity == 10)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
if (array.Length != 0)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
binaryHeap.Clear(true);
|
||||
if (binaryHeap.Capacity != 10 || binaryHeap.Count != 0)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ContainsTest()
|
||||
{
|
||||
binaryHeap.Add(100);
|
||||
if (!binaryHeap.Contains(100))
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ToArrayTest()
|
||||
{
|
||||
for(int i = 0; i < 1000; i++)
|
||||
{
|
||||
binaryHeap.Add(i);
|
||||
}
|
||||
int[] array = binaryHeap.ToArray();
|
||||
if(array.Length != binaryHeap.Count)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
if(array[0] != 0 && array[999] != 999)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void GetEnumeratorTest()
|
||||
{
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
binaryHeap.Add(i);
|
||||
}
|
||||
int count = 0;
|
||||
foreach(int value in binaryHeap)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(value);
|
||||
count++;
|
||||
}
|
||||
|
||||
if(count == binaryHeap.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
[Timeout(500)]
|
||||
public void DeleteMinTest()
|
||||
{
|
||||
try
|
||||
[TestMethod()]
|
||||
public void Serialize()
|
||||
{
|
||||
var tries = this.binaryHeap.Count;
|
||||
while (this.binaryHeap.Count > 0)
|
||||
BinaryHeap<int> binaryHeap2 = new BinaryHeap<int>();
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
if (tries == 0)
|
||||
binaryHeap.Add(i);
|
||||
}
|
||||
BinaryFormatter serializer = new BinaryFormatter();
|
||||
string s = string.Empty;
|
||||
using (var stream = new MemoryStream()) {
|
||||
serializer.Serialize(stream, binaryHeap);
|
||||
stream.Position = 0;
|
||||
binaryHeap2 = (BinaryHeap<int>)serializer.Deserialize(stream);
|
||||
}
|
||||
IEnumerator<int> binaryHeapEnum = binaryHeap.GetEnumerator();
|
||||
IEnumerator<int> binaryHeapEnum2 = binaryHeap2.GetEnumerator();
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
if (binaryHeapEnum.Current != binaryHeapEnum2.Current)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
|
||||
System.Diagnostics.Debug.WriteLine(this.binaryHeap.Remove());
|
||||
tries--;
|
||||
binaryHeapEnum.MoveNext();
|
||||
binaryHeapEnum2.MoveNext();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Assert.Fail(e.Message + "\n" + e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void MinMaxTest()
|
||||
{
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
this.binaryHeap.Add(i);
|
||||
}
|
||||
|
||||
if (this.binaryHeap.Min != 0 || this.binaryHeap.Max != 999)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ClearTest()
|
||||
{
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
this.binaryHeap.Add(i);
|
||||
}
|
||||
|
||||
this.binaryHeap.Clear();
|
||||
if (this.binaryHeap.Count > 0 || this.binaryHeap.Capacity != 160)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ClearTest2()
|
||||
{
|
||||
for (var i = 100; i < 200; i++)
|
||||
{
|
||||
this.binaryHeap.Add(i);
|
||||
}
|
||||
|
||||
this.binaryHeap.Clear(false);
|
||||
var array = this.binaryHeap.ToArray();
|
||||
if (this.binaryHeap.Count > 0 || this.binaryHeap.Capacity == 10)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
|
||||
if (array.Length != 0)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
|
||||
this.binaryHeap.Clear(true);
|
||||
if (this.binaryHeap.Capacity != 10 || this.binaryHeap.Count != 0)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ContainsTest()
|
||||
{
|
||||
this.binaryHeap.Add(100);
|
||||
if (!this.binaryHeap.Contains(100))
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ToArrayTest()
|
||||
{
|
||||
for(var i = 0; i < 1000; i++)
|
||||
{
|
||||
this.binaryHeap.Add(i);
|
||||
}
|
||||
|
||||
var array = this.binaryHeap.ToArray();
|
||||
if(array.Length != this.binaryHeap.Count)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
|
||||
if(array[0] != 0 && array[999] != 999)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void GetEnumeratorTest()
|
||||
{
|
||||
for (var i = 0; i < 1000; i++)
|
||||
{
|
||||
this.binaryHeap.Add(i);
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
foreach(var value in this.binaryHeap)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(value);
|
||||
count++;
|
||||
}
|
||||
|
||||
if(count == this.binaryHeap.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
@@ -1,395 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace System.Collections.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class CircularBufferTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void Constructor_WithCapacity_RespectsCapacity()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10);
|
||||
|
||||
buffer.Count.Should().Be(0);
|
||||
|
||||
for (var i = 0; i < 11; i++)
|
||||
{
|
||||
buffer.Add(i);
|
||||
}
|
||||
|
||||
buffer.Count.Should().Be(10);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Constructor_WithBuffer_ReturnsExpectedElements()
|
||||
{
|
||||
var array = new int[10];
|
||||
for(var i = 0; i < 10; i++)
|
||||
{
|
||||
array[i] = i;
|
||||
}
|
||||
|
||||
var buffer = new CircularBuffer<int>(array, 0, 9);
|
||||
|
||||
buffer.Count.Should().Be(10);
|
||||
buffer.Should().BeEquivalentTo(array);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Constructor_WithBuffer_RespectsOrder()
|
||||
{
|
||||
var expectedArray = new int[] { 3, 4, 5, 6, 7, 8, 9, 0, 1, 2 };
|
||||
var array = new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
|
||||
var buffer = new CircularBuffer<int>(array, 3, 2);
|
||||
|
||||
buffer.Count.Should().Be(10);
|
||||
buffer.Should().BeEquivalentTo(expectedArray);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Constructor_WithBuffer_RespectsInternalBuffer()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(new int[] { 0, 1, 2, 3, 4, 5 });
|
||||
|
||||
buffer.Count.Should().Be(6);
|
||||
buffer.Should().BeEquivalentTo(new int[] { 0, 1, 2, 3, 4, 5 });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AddItem_AddsItem()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
1
|
||||
};
|
||||
|
||||
buffer.Should().HaveCount(1);
|
||||
buffer.First().Should().Be(1);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AddItem_AddsItem_RespectsCapacity()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10
|
||||
};
|
||||
|
||||
buffer.Add(0);
|
||||
|
||||
buffer.Should().HaveCount(10);
|
||||
buffer.Last().Should().Be(0);
|
||||
buffer.First().Should().Be(2);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RemoveItem_RemovesDesiredItem()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10
|
||||
};
|
||||
|
||||
var result = buffer.Remove(5);
|
||||
|
||||
result.Should().BeTrue();
|
||||
buffer.Count.Should().Be(9);
|
||||
buffer.Should().BeEquivalentTo(new int[] { 1, 2, 3, 4, 6, 7, 8, 9, 10 });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RemoveItem_UnknownItem_DoesNotRemoveItem()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10
|
||||
};
|
||||
|
||||
var result = buffer.Remove(15);
|
||||
|
||||
result.Should().BeFalse();
|
||||
buffer.Count.Should().Be(10);
|
||||
buffer.Should().BeEquivalentTo(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Contains_ItemExists_ReturnsTrue()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10
|
||||
};
|
||||
|
||||
var result = buffer.Contains(5);
|
||||
|
||||
result.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Contains_ItemDoesNotExists_ReturnsFalse()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10
|
||||
};
|
||||
|
||||
var result = buffer.Contains(15);
|
||||
|
||||
result.Should().BeFalse();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Clear_ClearsBuffer()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10
|
||||
};
|
||||
|
||||
buffer.Clear();
|
||||
|
||||
buffer.Count.Should().Be(0);
|
||||
buffer.Should().BeEquivalentTo(Array.Empty<int>());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DeepClear_ClearsBuffer()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10
|
||||
};
|
||||
|
||||
buffer.DeepClear();
|
||||
|
||||
buffer.Count.Should().Be(0);
|
||||
buffer.Should().BeEquivalentTo(Array.Empty<int>());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Insert_FullBuffer_ThrowsException()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10
|
||||
};
|
||||
|
||||
var action = () =>
|
||||
{
|
||||
buffer.Insert(0, 1);
|
||||
};
|
||||
|
||||
action.Should().Throw<InvalidOperationException>();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Insert_ShouldInsertItemAtPosition()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
};
|
||||
|
||||
buffer.Insert(0, 0);
|
||||
|
||||
buffer.Should().BeEquivalentTo(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RemoveAt_RemovesExpectedItem()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
};
|
||||
|
||||
buffer.RemoveAt(0);
|
||||
|
||||
buffer.Should().BeEquivalentTo(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Indexer_ReturnsExpectedItem()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
};
|
||||
|
||||
buffer[5].Should().Be(5);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Indexer_SetsExpectedItem()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
};
|
||||
|
||||
buffer[6] = 5;
|
||||
|
||||
buffer.Should().BeEquivalentTo(new int[] { 0, 1, 2, 3, 4, 5, 5, 7, 8, 9 });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CircularBuffer_AddAndRemoveOperations_PerformAsExpected()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
};
|
||||
|
||||
buffer.Add(10);
|
||||
buffer.Remove(9);
|
||||
buffer.RemoveAt(5);
|
||||
buffer.Add(11);
|
||||
|
||||
buffer.Should().BeEquivalentTo(new int[] { 1, 2, 3, 4, 5, 7, 8, 10, 11 });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CircularBuffer_AddItems_RotatesBuffer()
|
||||
{
|
||||
var buffer = new CircularBuffer<int>(10)
|
||||
{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
};
|
||||
|
||||
for(var i = 0; i < 10; i++)
|
||||
{
|
||||
buffer.Add(i + 10);
|
||||
}
|
||||
|
||||
buffer.Should().BeEquivalentTo(new int[] { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 });
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user