From e4a17470deba7b7c5e933a10fd7cb4c952541a24 Mon Sep 17 00:00:00 2001 From: Charles Roddie Date: Thu, 5 May 2022 22:52:20 +0100 Subject: [PATCH 1/3] Add a solution so it can run --- DummyProject/DummyProject.sln | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 DummyProject/DummyProject.sln diff --git a/DummyProject/DummyProject.sln b/DummyProject/DummyProject.sln new file mode 100644 index 0000000..75c104f --- /dev/null +++ b/DummyProject/DummyProject.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32407.343 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SmallValueSet", "..\SmallValueSet\SmallValueSet.fsproj", "{3F5A0AE0-8CF7-4853-BE61-CA19155EE9A5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3F5A0AE0-8CF7-4853-BE61-CA19155EE9A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3F5A0AE0-8CF7-4853-BE61-CA19155EE9A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F5A0AE0-8CF7-4853-BE61-CA19155EE9A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3F5A0AE0-8CF7-4853-BE61-CA19155EE9A5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2F960B42-920E-45EE-B358-662E67BE68B5} + EndGlobalSection +EndGlobal From a05cda3f28f7c5133cce7c7c787c40f962c0bef1 Mon Sep 17 00:00:00 2001 From: Charles Roddie Date: Thu, 5 May 2022 23:04:42 +0100 Subject: [PATCH 2/3] add GenericIEquatableAdd --- SmallValueSet/Program.fs | 92 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/SmallValueSet/Program.fs b/SmallValueSet/Program.fs index f7ee24d..2599e85 100644 --- a/SmallValueSet/Program.fs +++ b/SmallValueSet/Program.fs @@ -327,6 +327,88 @@ type SmallSetInt64 (newValues: int64 seq) = member _.Values () = seq { for i in 0 .. count -> values[i] } + /// An array backed Set to be used with Value types where the +/// number of elements is small. It is meant to have an API +/// that is compatible with the HashSet<'T> collection +type SmallSetGenericIEquatable<'T when 'T :> System.IEquatable<'T>> (newValues: 'T seq) = + + let mutable count = Seq.length newValues + let mutable values = Array.zeroCreate (count * 2) + do newValues |> Seq.iteri (fun i v -> values[i] <- v) + + /// Adds an element to the SmallSet and returns a bool + /// indicating whether the element was added + member _.Add(newValue: 'T) = + let mutable exists = false + let mutable i = 0 + + while i < count && (not exists) do + exists <- (values.[i]:>IEquatable<'T>).Equals(newValue) + i <- i + 1 + + // We only need to add the element if it does not exist + if not exists then + + // Check if we have capacity in values to add the value + if count < values.Length then + // Add the new value to the end + values[count] <- newValue + // Update the number of elements stored in the SmallSet + count <- count + 1 + + else + // Create a new, larger array to contain the values + let newValues = Array.zeroCreate (values.Length * 2) + // Add the values from the previous store to the new one + values + |> Array.iteri (fun i v -> newValues[i] <- v) + // Add the new value to the end + newValues[values.Length] <- newValue + // Update the number of elements held by the SmallSet + count <- values.Length + 1 + // Swap out the internal store + values <- newValues + + exists + + /// Removes an element from the SmallSet returning a bool + /// indicating whether the SmallSet contained the element + member _.Remove(value: 'T) = + + let mutable i = 0 + let mutable isFound = false + + while i < count && (not isFound) do + + // Check if we have found the value of interest + if (values[i]:>IEquatable<'T>).Equals(value) then + // We overwrite the removed value with the last value + // in the SmallSet + values[i] <- values[count - 1] + // We decrement the count to indicate the new number of + // elements in the small set + count <- count - 1 + // We update the isFound flag to break out of the loop + isFound <- true + + i <- i + 1 + + isFound + + /// Returns an int indicating the number of elements in the SmallSet + member _.Count = count + + /// Retrieve an item by index from the SmallSet + member _.Item + with get k = + if k > count - 1 then + raise (IndexOutOfRangeException ()) + else + values[k] + + // A simple way to iterate through the values in the SmallSet. + member _.Values () = + seq { for i in 0 .. count -> values[i] } [] type Benchmarks () = @@ -350,6 +432,7 @@ type Benchmarks () = let smallSetFastComparer = SmallSetFastComparer values let smallSetEqualityComparer = SmallSetEqualityComparer values let smallSetInt64 = SmallSetInt64 values + let smallSetGenericIEquatable = SmallSetGenericIEquatable values [] member _.HashSetAdd () = @@ -396,6 +479,15 @@ type Benchmarks () = result + [] + member _.SmallSetGenericIEquatableAdd () = + let mutable result = false + + for elem in addValues do + result <- smallSetInt64.Add elem + + result + [] member _.HashSetRemove () = let mutable result = false From d1b8697cc07293ac095107576b9ebd741ac8282b Mon Sep 17 00:00:00 2001 From: Matthew Crews Date: Thu, 5 May 2022 20:29:19 -0700 Subject: [PATCH 3/3] updated tests --- SmallValueSet/Program.fs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/SmallValueSet/Program.fs b/SmallValueSet/Program.fs index 2599e85..64eb8b3 100644 --- a/SmallValueSet/Program.fs +++ b/SmallValueSet/Program.fs @@ -484,7 +484,7 @@ type Benchmarks () = let mutable result = false for elem in addValues do - result <- smallSetInt64.Add elem + result <- smallSetGenericIEquatable.Add elem result @@ -533,6 +533,15 @@ type Benchmarks () = result + [] + member _.SmallSetGenericIEquatableRemove () = + let mutable result = false + + for elem in removeValues do + result <- smallSetGenericIEquatable.Remove elem + + result + let args = Environment.GetCommandLineArgs()[1..]