Skip to content

Commit 198c30a

Browse files
committed
"Final" version of Array.filter, including test
- Small and large array edge case optimizations included - Broke functionality into multiple functions
1 parent adfab79 commit 198c30a

File tree

2 files changed

+216
-100
lines changed

2 files changed

+216
-100
lines changed

src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,64 @@ type ArrayModule() =
724724
let nullArr = null:string[]
725725
CheckThrowsArgumentNullException (fun () -> Array.filter funcStr nullArr |> ignore)
726726

727-
()
727+
()
728+
729+
[<Test>]
730+
member this.Filter2 () =
731+
// The Array.filter algorith uses a bitmask as a temporary storage mechanism
732+
// for which elements to filter. This introduces some possible error conditions
733+
// around how the filter is filled and subsequently used, so filter test
734+
// does a pretty exhaustive test suite.
735+
// It works by first generating arrays which consist of sequences of unique
736+
// positive and negative numbers, as per arguments, it then filters for the
737+
// positive values, and then compares the results agains the original array.
738+
739+
let makeTestArray size posLength negLength startWithPos startFromEnd =
740+
let array = Array.zeroCreate size
741+
742+
let mutable sign = if startWithPos then 1 else -1
743+
let mutable count = if startWithPos then posLength else negLength
744+
for i = 1 to size do
745+
let idx = if startFromEnd then size-i else i-1
746+
array.[idx] <- (idx+1) * sign
747+
count <- count - 1
748+
if count <= 0 then
749+
sign <- sign * -1
750+
count <- if sign > 0 then posLength else negLength
751+
752+
array
753+
754+
let checkFilter filter (array:array<_>) =
755+
let filtered = array |> filter (fun n -> n > 0)
756+
757+
let mutable idx = 0
758+
for item in filtered do
759+
while array.[idx] < item do
760+
idx <- idx + 1
761+
if item <> array.[idx] then
762+
Assert.Fail ()
763+
idx <- idx + 1
764+
while idx < array.Length do
765+
if array.[idx] > 0 then
766+
Assert.Fail ()
767+
idx <- idx + 1
768+
769+
let checkCombinations filter maxSize =
770+
for size = 0 to maxSize do
771+
for posLength = 1 to size do
772+
for negLength = 1 to size do
773+
for startWithPos in [true; false] do
774+
for startFromEnd in [true; false] do
775+
let testArray = makeTestArray size posLength negLength startWithPos startFromEnd
776+
checkFilter filter testArray
777+
778+
// this could probably be a bit smaller, but needs to at least be > 64 to test chunk copying
779+
// of data, and > 96 gives a safer feel, so settle on a nice decimal rounding of one hundred
780+
// to appease those with digits.
781+
let suitableTestMaxLength = 100
782+
783+
checkCombinations Array.filter suitableTestMaxLength
784+
728785

729786

730787
[<Test>]

0 commit comments

Comments
 (0)