diff --git a/appveyor.yml b/appveyor.yml
index 855f34f..53ce8d1 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,7 +1,17 @@
-image: Visual Studio 2017
+image: Visual Studio 2019
+
+init:
+ - git config --global core.autocrlf true
+
+environment:
+ matrix:
+ - solution: Semester4/Lazy/Lazy.sln
before_build:
- - nuget restore semester2/6.1/HW6T2.sln
+ - nuget restore %solution%
build:
- project: semester2/2.3/2.3.sln
+ project: $(solution)
+
+test_script:
+ - dotnet test %solution%
diff --git a/semester4/Lazy/Lazy.Tests/Lazy.Tests.fsproj b/semester4/Lazy/Lazy.Tests/Lazy.Tests.fsproj
new file mode 100644
index 0000000..b266781
--- /dev/null
+++ b/semester4/Lazy/Lazy.Tests/Lazy.Tests.fsproj
@@ -0,0 +1,26 @@
+
+
+
+ netcoreapp3.1
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/semester4/Lazy/Lazy.Tests/LazyTests.fs b/semester4/Lazy/Lazy.Tests/LazyTests.fs
new file mode 100644
index 0000000..fae4601
--- /dev/null
+++ b/semester4/Lazy/Lazy.Tests/LazyTests.fs
@@ -0,0 +1,96 @@
+module Lazy.Tests
+
+open System.Threading
+open NUnit.Framework
+open FsUnit
+open LazyFactory
+open ILazy
+
+[]
+let ``simple int single thread lazy test`` () =
+ let holder = LazyFactory.CreateSingleThreadLazy <| fun () -> 1
+ holder.Get() |> should equal 1
+
+[]
+let ``simple string single thread lazy test`` () =
+ let holder = LazyFactory.CreateSingleThreadLazy <| fun () -> "h" + "e" + "l" + "l" + "o"
+ holder.Get() |> should equal "hello"
+
+[]
+let ``array single thread lazy test`` () =
+ let holder =
+ LazyFactory>
+ .CreateSingleThreadLazy(fun () ->
+ [ 2; 4; 1; 3; 4; 52; 9; 17; 33; 36 ]
+ |> List.map (fun x -> x * 1000)
+ |> List.filter (fun x -> x % 3 = 0))
+
+ holder.Get() |> should equal [ 3000; 9000; 33000; 36000 ]
+
+[]
+let ``called once single thread test`` () =
+ let mutable counter = 0
+ let holder = LazyFactory.CreateSingleThreadLazy(fun () -> counter <- counter + 1)
+ for i in 1..100 do
+ holder.Get()
+ counter |> should equal 1
+
+[]
+let ``called once test multi thread with lock`` () =
+ let mutable counter = ref 0
+ let holder = LazyFactory.LockMultiThreadLazy(fun () -> Interlocked.Increment(counter))
+ for i in 1..100 do
+ holder.Get() |> ignore
+ counter.contents |> should equal 1
+
+[]
+let ``called once test lock free with lock`` () =
+ let mutable counter = ref 0
+ let holder = LazyFactory.LockFreeLazy(fun () -> Interlocked.Increment(counter))
+ for i in 1..100 do
+ holder.Get() |> ignore
+ counter.contents |> should equal 1
+
+[]
+let ``lot of thread multi thread lock test`` () =
+ let holder = LazyFactory.LockMultiThreadLazy(fun () -> obj())
+ let toCompare = holder.Get()
+ for i in 1..100500 do
+ holder.Get() |> should equal toCompare
+
+[]
+let ``lot of thread lock free test`` () =
+ let holder = LazyFactory.LockFreeLazy(fun () -> obj())
+ let toCompare = holder.Get()
+ for i in 1..100500 do
+ holder.Get() |> should equal toCompare
+
+[]
+let ``simple work lock free test`` () =
+ let holder = LazyFactory.LockFreeLazy(fun () -> 1)
+ holder.Get() |> should equal 1
+
+[]
+let ``simple work multi thread lock test`` () =
+ let holder = LazyFactory.LockMultiThreadLazy(fun () -> 1)
+ holder.Get() |> should equal 1
+
+let LazyTestHelper (object : ILazy<'a>, expected) =
+ let threadWork () =
+ object.Get() |> should equal expected
+
+ let threads = Array.init 10 (fun _ -> Thread(threadWork))
+
+ for thread in threads do
+ thread.Start()
+
+ for thread in threads do
+ thread.Join()
+
+[]
+let ``multithread lock free lazy`` () =
+ LazyTestHelper(LazyFactory.LockFreeLazy(fun _ -> "hello" + " " + "world"), "hello world")
+
+[]
+let ``multithread lock lazy`` () =
+ LazyTestHelper(LazyFactory.LockMultiThreadLazy(fun _ -> "hello" + " " + "world"), "hello world")
\ No newline at end of file
diff --git a/semester4/Lazy/Lazy.sln b/semester4/Lazy/Lazy.sln
new file mode 100644
index 0000000..2396cd1
--- /dev/null
+++ b/semester4/Lazy/Lazy.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Lazy", "Lazy\Lazy.fsproj", "{F2726A51-E1AF-4B6D-8F33-91D669445C02}"
+EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Lazy.Tests", "Lazy.Tests\Lazy.Tests.fsproj", "{41A66F38-8DB3-473C-B876-9E7C87CAF01F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F2726A51-E1AF-4B6D-8F33-91D669445C02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F2726A51-E1AF-4B6D-8F33-91D669445C02}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F2726A51-E1AF-4B6D-8F33-91D669445C02}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F2726A51-E1AF-4B6D-8F33-91D669445C02}.Release|Any CPU.Build.0 = Release|Any CPU
+ {41A66F38-8DB3-473C-B876-9E7C87CAF01F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {41A66F38-8DB3-473C-B876-9E7C87CAF01F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {41A66F38-8DB3-473C-B876-9E7C87CAF01F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {41A66F38-8DB3-473C-B876-9E7C87CAF01F}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/semester4/Lazy/Lazy/ILazy.fs b/semester4/Lazy/Lazy/ILazy.fs
new file mode 100644
index 0000000..5b8cec2
--- /dev/null
+++ b/semester4/Lazy/Lazy/ILazy.fs
@@ -0,0 +1,7 @@
+module ILazy
+
+/// Interface that describes lazy computations
+type ILazy<'a> =
+ /// If Get() called first time, calculates func and returns result,
+ /// otherwise, returns already computed function
+ abstract member Get: unit -> 'a
\ No newline at end of file
diff --git a/semester4/Lazy/Lazy/Lazy.fs b/semester4/Lazy/Lazy/Lazy.fs
new file mode 100644
index 0000000..529469e
--- /dev/null
+++ b/semester4/Lazy/Lazy/Lazy.fs
@@ -0,0 +1,17 @@
+module SingleThreadLazy
+
+open ILazy
+
+/// Simple lazy class realization for single thread work
+type SingleThreadLazy<'a>(supplier : unit -> 'a) =
+ let mutable result = None
+ interface ILazy<'a> with
+
+ /// If Get() called first time, calculates func and returns result,
+ /// otherwise, returns already computed function
+ member this.Get() =
+ match result with
+ | Some x -> x
+ | None ->
+ result <- Some(supplier())
+ result.Value
\ No newline at end of file
diff --git a/semester4/Lazy/Lazy/Lazy.fsproj b/semester4/Lazy/Lazy/Lazy.fsproj
new file mode 100644
index 0000000..01caaa0
--- /dev/null
+++ b/semester4/Lazy/Lazy/Lazy.fsproj
@@ -0,0 +1,15 @@
+
+
+
+ netcoreapp3.1
+
+
+
+
+
+
+
+
+
+
+
diff --git a/semester4/Lazy/Lazy/LazyFactory.fs b/semester4/Lazy/Lazy/LazyFactory.fs
new file mode 100644
index 0000000..f1e0f45
--- /dev/null
+++ b/semester4/Lazy/Lazy/LazyFactory.fs
@@ -0,0 +1,17 @@
+module LazyFactory
+
+open ILazy
+open SingleThreadLazy
+open LockMultiThreadLazy
+open LockFreeLazy
+
+/// Creates lazy classes of various types
+type LazyFactory<'a> =
+ /// Creates single thread lazy object
+ static member CreateSingleThreadLazy supplier = SingleThreadLazy<'a>(supplier) :> ILazy<'a>
+
+ /// Creates multithread lazy object that works without locks
+ static member LockFreeLazy supplier = LockFreeLazy<'a>(supplier) :> ILazy<'a>
+
+ /// Creates simple multithread lazy based on locks
+ static member LockMultiThreadLazy supplier = LockMultiThreadLazy<'a>(supplier) :> ILazy<'a>
\ No newline at end of file
diff --git a/semester4/Lazy/Lazy/LockFreeLazy.fs b/semester4/Lazy/Lazy/LockFreeLazy.fs
new file mode 100644
index 0000000..71cb777
--- /dev/null
+++ b/semester4/Lazy/Lazy/LockFreeLazy.fs
@@ -0,0 +1,21 @@
+module LockFreeLazy
+
+open ILazy
+open System.Threading
+
+/// Simple lazy class realization for multi thread work
+/// without locks
+type LockFreeLazy<'a>(supplier : unit -> 'a) =
+ let mutable desiredResult = None
+ let mutable startResult = None
+ let mutable computed = false
+ interface ILazy<'a> with
+
+ /// If Get() called first time, calculates func and returns result,
+ /// otherwise, returns already computed function
+ member this.Get() =
+ if not computed then
+ desiredResult <- Some(supplier())
+ Interlocked.CompareExchange(ref startResult, desiredResult, None) |> ignore
+ computed <- true
+ desiredResult.Value
\ No newline at end of file
diff --git a/semester4/Lazy/Lazy/LockMultithreadLazy.fs b/semester4/Lazy/Lazy/LockMultithreadLazy.fs
new file mode 100644
index 0000000..305a0fb
--- /dev/null
+++ b/semester4/Lazy/Lazy/LockMultithreadLazy.fs
@@ -0,0 +1,23 @@
+module LockMultiThreadLazy
+
+open ILazy
+
+/// Simple lazy class realization for multi thread work
+/// based on lock
+type LockMultiThreadLazy<'a>(supplier : unit->'a) =
+ let mutable result = None
+ let locker = obj()
+ interface ILazy<'a> with
+ /// If Get() called first time, calculates func and returns result,
+ /// otherwise, returns already computed function
+
+ member this.Get() =
+ match result with
+ | Some x -> x
+ | None ->
+ lock locker <| fun () ->
+ match result with
+ | Some x -> x
+ | None ->
+ result <- Some(supplier())
+ result.Value
\ No newline at end of file