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 diff --git a/SmallValueSet/Program.fs b/SmallValueSet/Program.fs index f7ee24d..64eb8b3 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 <- smallSetGenericIEquatable.Add elem + + result + [] member _.HashSetRemove () = let mutable result = false @@ -441,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..]