Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
422 changes: 0 additions & 422 deletions .gitignore

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions HW2/HW2.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyEvaluation", "LazyEvaluation\LazyEvaluation.csproj", "{D2A3863F-D69C-419E-9580-826C8718A7E5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LazyEvaluation.Test", "LazyEvaluation.Test\LazyEvaluation.Test.csproj", "{C9B07A5A-EAD9-461C-B638-858E14BD4E7E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D2A3863F-D69C-419E-9580-826C8718A7E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D2A3863F-D69C-419E-9580-826C8718A7E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2A3863F-D69C-419E-9580-826C8718A7E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2A3863F-D69C-419E-9580-826C8718A7E5}.Release|Any CPU.Build.0 = Release|Any CPU
{C9B07A5A-EAD9-461C-B638-858E14BD4E7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C9B07A5A-EAD9-461C-B638-858E14BD4E7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C9B07A5A-EAD9-461C-B638-858E14BD4E7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C9B07A5A-EAD9-461C-B638-858E14BD4E7E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
40 changes: 40 additions & 0 deletions HW2/LazyEvaluation.Test/LazyEvaluation.Test.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageReference Include="NUnit" Version="3.14.0"/>
<PackageReference Include="NUnit.Analyzers" Version="3.9.0"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
</ItemGroup>

<ItemGroup>
<Using Include="NUnit.Framework"/>
</ItemGroup>


<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<AdditionalFiles Include="stylecop.json" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\LazyEvaluation\LazyEvaluation.csproj" />
</ItemGroup>

</Project>
97 changes: 97 additions & 0 deletions HW2/LazyEvaluation.Test/LazyEvaluationTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// <copyright file="LazyEvaluationTest.cs" company="khusainovilas">
// Copyright (c) khusainovilas. All rights reserved.
// </copyright>

namespace LazyEvaluation.Test;

/// <summary>
/// Unit tests for lazy evaluation.
/// </summary>
public abstract class LazyEvaluationTest
{
/// <summary>
/// Verifies that the supplier delegate is called exactly one time.
/// </summary>
[Test]
public void Lazy_Get_NonNullSupplier_SupplierCalledOnce()
{
var callCount = 0;

var supplier = new Func<string?>(() =>
{
callCount++;
return "test";
});

var lazy = this.CreateLazy(supplier);

var result1 = lazy.Get();
var result2 = lazy.Get();

Assert.Multiple(() =>
{
Assert.That(result1, Is.EqualTo("test"));
Assert.That(result2, Is.EqualTo("test"));
Assert.That(callCount, Is.EqualTo(1));
});
}

/// <summary>
/// Verifies that multiple calls to Get() return the same result.
/// </summary>
[Test]
public void Lazy_Get_SimpleString_NonNullSupplier_SameResult()
{
var supplier = new Func<string?>(() => "test");
var lazy = this.CreateLazy(supplier);

var result1 = lazy.Get();
var result2 = lazy.Get();

Assert.That(result2, Is.EqualTo(result1));
}

/// <summary>
/// Verifies that constructing with a null supplier throws ArgumentNullException.
/// </summary>
[Test]
public void Lazy_Constructor_NullSupplier_ThrowsException()
{
Assert.Throws<ArgumentNullException>(() =>
{
Func<string?> supplier = null!;
this.CreateLazy(supplier);
});
}

/// <summary>
/// Verifies that Get() correctly handles a null result from the supplier.
/// </summary>
[Test]
public void Lazy_Get_NullResultSupplier_ReturnsNull()
{
var callCount = 0;
var supplier = new Func<string?>(() =>
{
callCount++;
return null;
});

var lazy = this.CreateLazy(supplier);

Assert.Multiple(() =>
{
Assert.That(lazy.Get(), Is.Null);
Assert.That(lazy.Get(), Is.Null);
Assert.That(callCount, Is.EqualTo(1));
});
}

/// <summary>
/// abstract method for creating an ILazy instance.
/// </summary>
/// <param name="supplier">function responsible for computing the value.</param>
/// <typeparam name="T">the type of the computed value.</typeparam>
/// <returns>a new ILazy instance.</returns>
protected abstract ILazy<T> CreateLazy<T>(Func<T> supplier);
}
64 changes: 64 additions & 0 deletions HW2/LazyEvaluation.Test/LazyMultiThreadedTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// <copyright file="LazyMultiThreadedTest.cs" company="khusainovilas">
// Copyright (c) khusainovilas. All rights reserved.
// </copyright>

namespace LazyEvaluation.Test;

/// <summary>
/// Unit tests for LazyMultiThreaded implementation.
/// </summary>
public class LazyMultiThreadedTest : LazyEvaluationTest
{
/// <summary>
/// Verifies that the supplier is called exactly once during concurrent Get() calls in LazyMultiThreaded.
/// </summary>
[Test]
public void LazyMultiThreaded_Get_String_SingleSupplierCall()
{
var callCount = 0;
var lazy = this.CreateLazy(() =>
{
Interlocked.Increment(ref callCount);
return "test";
});

const int threadsCount = 100;
var threads = new Thread[threadsCount];
var results = new string[threadsCount];

var startEvent = new ManualResetEvent(false);

for (var i = 0; i < threadsCount; i++)
{
var index = i;
threads[i] = new Thread(() =>
{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

здесь как раз нужно startEvent выставить, чтобы потоки остановились

results[index] = lazy.Get();
});
}

startEvent.Set();

foreach (var thread in threads)
{
thread.Start();
}

foreach (var thread in threads)
{
thread.Join();
}

Assert.Multiple(() =>
{
Assert.That(results, Has.All.EqualTo("test"));
Assert.That(callCount, Is.EqualTo(1));
});
}

/// <inheritdoc/>
protected override ILazy<T> CreateLazy<T>(Func<T> supplier)
{
return new LazyMultiThreaded<T>(supplier);
}
}
51 changes: 51 additions & 0 deletions HW2/LazyEvaluation.Test/LazySingleThreadedTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// <copyright file="LazySingleThreadedTest.cs" company="khusainovilas">
// Copyright (c) khusainovilas. All rights reserved.
// </copyright>

namespace LazyEvaluation.Test;

/// <summary>
/// Unit tests for LazySingleThreaded implementation.
/// </summary>
public class LazySingleThreadedTest : LazyEvaluationTest
{
/// <summary>
/// Test for correct work Get() with double.
/// </summary>
[Test]
public void LazySingleThreaded_Get_Double_ReturnsCorrectValue()
{
var callCount = 0;
var lazy = this.CreateLazy(() =>
{
callCount++;
return 1.5;
});

var result1 = lazy.Get();
var result2 = lazy.Get();

Assert.Multiple(() =>
{
Assert.That(result1, Is.EqualTo(1.5).Within(1e-9));
Assert.That(result2, Is.EqualTo(1.5).Within(1e-9));
Assert.That(callCount, Is.EqualTo(1));
});
}

/// <summary>
/// Test for handling exception from supplier in Get().
/// </summary>
[Test]
public void LazySingleThreaded_Get_Double_ThrowsException()
{
var lazy = this.CreateLazy<double?>(() => throw new InvalidOperationException("Supplier failed"));
Assert.Throws<InvalidOperationException>(() => lazy.Get());
}

/// <inheritdoc/>
protected override ILazy<T> CreateLazy<T>(Func<T> supplier)
{
return new LazySingleThreaded<T>(supplier);
}
}
9 changes: 9 additions & 0 deletions HW2/LazyEvaluation.Test/stylecop.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
"settings": {
"documentationRules": {
"companyName": "khusainovilas",
"copyrightText": "Copyright (c) {companyName}. All rights reserved."
}
}
}
18 changes: 18 additions & 0 deletions HW2/LazyEvaluation/ILazy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// <copyright file="ILazy.cs" company="khusainovilas">
// Copyright (c) khusainovilas. All rights reserved.
// </copyright>

namespace LazyEvaluation;

/// <summary>
/// Defines a contract for lazy evaluation, where a value of type T is computed only on the first call and cached for subsequent access.
/// </summary>
/// <typeparam name="T">The type of the value to be lazily computed.</typeparam>
public interface ILazy<T>
{
/// <summary>
/// Gets the lazily computed value. The value is computed on the first call and cached for subsequent calls.
/// </summary>
/// <returns>The computed or cached value.</returns>
T Get();
}
21 changes: 21 additions & 0 deletions HW2/LazyEvaluation/LazyEvaluation.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<AdditionalFiles Include="stylecop.json" />
</ItemGroup>

</Project>
49 changes: 49 additions & 0 deletions HW2/LazyEvaluation/LazyMultiThreaded.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// <copyright file="LazyMultiThreaded.cs" company="khusainovilas">
// Copyright (c) khusainovilas. All rights reserved.
// </copyright>

namespace LazyEvaluation;

/// <summary>
/// A multithreaded implementation of the ILazy interface for lazy evaluation.
/// </summary>
/// <typeparam name="T">The type of the value produced by the lazy computation.</typeparam>
public class LazyMultiThreaded<T> : ILazy<T>
{
private readonly object lockObject = new();
private Func<T>? supplier;
private T? value;
private volatile bool isComputed;

/// <summary>
/// Initializes a new instance of the <see cref="LazyMultiThreaded{T}"/> class.
/// </summary>
/// <param name="supplier">The delegate that produces the value when needed.</param>
public LazyMultiThreaded(Func<T> supplier)
{
this.supplier = supplier ?? throw new ArgumentNullException(nameof(supplier));
}

/// <inheritdoc/>
public T Get()
{
if (this.isComputed)
{
return this.value!;
}

lock (this.lockObject)
{
if (this.isComputed)
{
return this.value!;
}

this.value = this.supplier!();
this.isComputed = true;
this.supplier = null!;
}

return this.value!;
}
}
Loading