Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
5aa66a1
Helper function for FastGenericEqualityComparerTable
manofstick Jun 5, 2018
f6d7d72
Use the default equality comparer where applicable
manofstick Jun 5, 2018
08a64dd
Avoid calls to GenericEqualityObj for known types
manofstick Jun 5, 2018
75de86f
Avoid boxing in the "standard" use of GenericEqualityWithComparerIntr…
manofstick Jun 6, 2018
eda7759
Added method to avoid tail calls
manofstick Jun 6, 2018
2005004
Implemented hashing
manofstick Jun 6, 2018
b385c0f
Additional use of EqualityComparer.Default
manofstick Jun 6, 2018
e3628ff
Consistent naming
manofstick Jun 6, 2018
1847f5f
Fixed up by mix up my ERs with my PERs!
manofstick Jun 7, 2018
9b3fb94
Apply De Morgan's law to make it a bit cleaner
manofstick Jun 7, 2018
ffcbe16
Argh, got the PER and ER mixed up even when I tried to fix. Now good …
manofstick Jun 8, 2018
f3edd75
Removed custom delegates by using System.Func
manofstick Jun 8, 2018
b84e72a
Disallow optimization on Nullable types
manofstick Jun 8, 2018
7bb1729
More inclusive check for canUseDefaultEqualityComparer
manofstick Jun 9, 2018
8d3a9dd
Updated il output files
manofstick Jun 9, 2018
2d0eb4e
Removed IERorPER by splitting calling class into 2, and added helper …
manofstick Jun 11, 2018
d47f69b
Changed it all to used EqualityComparer derived classes and restored …
manofstick Jun 13, 2018
d6f6912
Removed comparers that matched EqualityComparer<>.Default and code re…
manofstick Jun 14, 2018
a85ecb4
Added additional types where EqualityComparer.Default can be used
manofstick Jun 16, 2018
2386aa8
Save unnecessary type checks when more information is known
manofstick Jun 16, 2018
c95dc5e
Removed now unused objects, and other minor cleanup
manofstick Jun 18, 2018
3a9ec3a
Modified Optimizer to manually inline GenericEqualityIntrinsic and fr…
manofstick Jun 23, 2018
fe51bf9
Fixed SurfaceArea
manofstick Jun 23, 2018
a37b3d5
Ensure FSharp.Core has the optimization functions (and added comments)
manofstick Jun 23, 2018
c489af6
Remove IL bloat from this PR as per https://github.com/Microsoft/visu…
manofstick Jun 25, 2018
853d039
Remove null checks for IStructuralEquality Value Types
manofstick Jun 26, 2018
163d1e2
Consolidated Type Specific Array Equality functions
manofstick Jun 27, 2018
d5830e0
Fix compiler call via FSharpFunc.Invoke rather than direct
manofstick Jun 27, 2018
26ed397
Replaced duplicated GetHashCode code with inline function
manofstick Jun 28, 2018
ad78ec0
Common array EqualityComparers (for types that previously had special…
manofstick Jun 28, 2018
2cc05f0
Fix regression in regards to hash code on fast-path covariant arrays …
manofstick Jul 11, 2018
858cdf3
Similar treatment within prim-types for Comparer as #5112 was for Equ…
manofstick Jul 1, 2018
fb5427c
Moved throwing exceptions closer
manofstick Jul 2, 2018
b8f5ac8
Added comparison usage, so could remove exception catching logic when…
manofstick Jul 2, 2018
780f303
Consolidated functions
manofstick Jul 3, 2018
e3c1869
Consolidated ArrayComparisons and addressed issue #5263
manofstick Jul 3, 2018
508111f
Fixed bug introduced in #5278 where an unstable sort could be used wh…
manofstick Jul 18, 2018
4090b2b
Removed now unnecessary optimization from stableSortWithKeysAndComparer
manofstick Jul 19, 2018
291dd75
Moved isRecordType down to prim-types.fs (internal only)
manofstick Jul 8, 2018
ca7e290
Moved enough of reflect.fs to get Record fields
manofstick Jul 8, 2018
f3f9aa3
Moved reflection functions for Union types into prim-types.fs
manofstick Jul 9, 2018
e38a1e3
Removed methods from prim-types.fsi that are now just used internally
manofstick Jul 9, 2018
0492980
Used the reflection functions to handle records and unions
manofstick Jul 9, 2018
bf784e5
Added check for fsharp value types
manofstick Jul 9, 2018
ccd2156
Fixed struct check where a [<DefaultValue>] field is used.
manofstick Jul 10, 2018
3a4f0b7
Minor shift in logic order for less comparisons
manofstick Jul 11, 2018
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
31 changes: 16 additions & 15 deletions src/fsharp/FSharp.Core/local.fs
Original file line number Diff line number Diff line change
Expand Up @@ -990,8 +990,12 @@ module internal Array =

open System

let inline fastComparerForArraySort<'t when 't : comparison> () =
LanguagePrimitives.FastGenericComparerCanBeNull<'t>
let inline getInternalComparer<'t when 't : comparison> () =
// Previously a "comparer" was returned the could be null, which was for optimized Array.Sort
// but we now mainly return Comparer.Default (and FastGenericComparerInternal more so)
// which is also optimized in Array.Sort
// ** this comment can be destroyed sometime in the future, it is just as a breadcrumb for review **
LanguagePrimitives.FastGenericComparerInternal<'t>

// The input parameter should be checked by callers if necessary
let inline zeroCreateUnchecked (count:int) =
Expand Down Expand Up @@ -1089,26 +1093,26 @@ module internal Array =
let keys = zeroCreateUnchecked array.Length
for i = 0 to array.Length - 1 do
keys.[i] <- projection array.[i]
Array.Sort<_,_>(keys, array, fastComparerForArraySort())
Array.Sort<_,_>(keys, array, getInternalComparer())

let unstableSortInPlace (array : array<'T>) =
let len = array.Length
if len < 2 then ()
else Array.Sort<_>(array, fastComparerForArraySort())
else Array.Sort<_>(array, getInternalComparer())

let stableSortWithKeysAndComparer (cFast:IComparer<'Key>) (c:IComparer<'Key>) (array:array<'T>) (keys:array<'Key>) =
let stableSortWithKeysAndComparer (c:IComparer<'Key>) (array:array<'T>) (keys:array<'Key>) =
// 'places' is an array or integers storing the permutation performed by the sort
let places = zeroCreateUnchecked array.Length
for i = 0 to array.Length - 1 do
places.[i] <- i
System.Array.Sort<_,_>(keys, places, cFast)
System.Array.Sort<_,_>(keys, places, c)
// 'array2' is a copy of the original values
let array2 = (array.Clone() :?> array<'T>)

// Walk through any chunks where the keys are equal
let mutable i = 0
let len = array.Length
let intCompare = fastComparerForArraySort<int>()
let intCompare = getInternalComparer<int>()

while i < len do
let mutable j = i
Expand All @@ -1123,9 +1127,8 @@ module internal Array =
i <- j

let stableSortWithKeys (array:array<'T>) (keys:array<'Key>) =
let cFast = fastComparerForArraySort()
let c = LanguagePrimitives.FastGenericComparer<'Key>
stableSortWithKeysAndComparer cFast c array keys
let c = getInternalComparer()
stableSortWithKeysAndComparer c array keys

let stableSortInPlaceBy (projection: 'T -> 'U) (array : array<'T>) =
let len = array.Length
Expand All @@ -1141,13 +1144,11 @@ module internal Array =
let len = array.Length
if len < 2 then ()
else
let cFast = LanguagePrimitives.FastGenericComparerCanBeNull<'T>
match cFast with
| null ->
if LanguagePrimitives.EquivalentForStableAndUnstableSort<'T> then
// An optimization for the cases where the keys and values coincide and do not have identity, e.g. are integers
// In this case an unstable sort is just as good as a stable sort (and faster)
Array.Sort<_,_>(array, null)
| _ ->
else
// 'keys' is an array storing the projected keys
let keys = (array.Clone() :?> array<'T>)
stableSortWithKeys array keys
Expand All @@ -1158,7 +1159,7 @@ module internal Array =
let keys = (array.Clone() :?> array<'T>)
let comparer = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(comparer)
let c = { new IComparer<'T> with member __.Compare(x,y) = comparer.Invoke(x,y) }
stableSortWithKeysAndComparer c c array keys
stableSortWithKeysAndComparer c array keys

let inline subUnchecked startIndex count (array : 'T[]) =
let res = zeroCreateUnchecked count : 'T[]
Expand Down
1,432 changes: 961 additions & 471 deletions src/fsharp/FSharp.Core/prim-types.fs

Large diffs are not rendered by default.

35 changes: 34 additions & 1 deletion src/fsharp/FSharp.Core/prim-types.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -952,7 +952,10 @@ namespace Microsoft.FSharp.Core
val inline FastGenericComparer<'T> : System.Collections.Generic.IComparer<'T> when 'T : comparison

/// <summary>Make an F# comparer object for the given type, where it can be null if System.Collections.Generic.Comparer&lt;'T&gt;.Default</summary>
val internal FastGenericComparerCanBeNull<'T> : System.Collections.Generic.IComparer<'T> when 'T : comparison
val internal FastGenericComparerInternal<'T> : System.Collections.Generic.Comparer<'T> when 'T : comparison

/// As an optimization, determine if a fast unstable sort can be used with equivalent results
val internal EquivalentForStableAndUnstableSort<'T> : bool

/// <summary>Make an F# hash/equality object for the given type</summary>
val inline FastGenericEqualityComparer<'T> : System.Collections.Generic.IEqualityComparer<'T> when 'T : equality
Expand Down Expand Up @@ -1236,8 +1239,38 @@ namespace Microsoft.FSharp.Core
//[<CompilerMessage("This function is for use by compiled F# code and should not be used directly", 1204, IsHidden=true)>]
val inline SetArray4D : target:'T[,,,] -> index1:int -> index2:int -> index3:int -> index4:int -> value:'T -> unit

module internal Reflection =
val internal tupleNames : string []
val internal isTupleType : Type -> bool
val internal tryFindSourceConstructFlagsOfType : Type * byref<SourceConstructFlags> -> bool
val internal fieldPropsOfRecordType : Type * System.Reflection.BindingFlags -> System.Reflection.PropertyInfo[]
val internal isRecordType : Type * System.Reflection.BindingFlags -> bool
val internal getUnionTypeTagNameMap : Type * System.Reflection.BindingFlags -> (int*string)[]
val internal fieldsPropsOfUnionCase : Type * int* System.Reflection.BindingFlags -> System.Reflection.PropertyInfo[]
val internal isUnionType : Type * System.Reflection.BindingFlags -> bool

/// <summary>The F# compiler emits calls to some of the functions in this module as part of the compiled form of some language constructs</summary>
module HashCompare =
[<AbstractClass; Sealed>]
type FSharpEqualityComparer_ER<'T> =
static member EqualityComparer : System.Collections.Generic.EqualityComparer<'T>

[<AbstractClass; Sealed>]
type FSharpEqualityComparer_PER<'T> =
static member EqualityComparer : System.Collections.Generic.EqualityComparer<'T>

/// <summary>A primitive entry point used by the F# compiler for optimization purposes.</summary>
[<CompilerMessage("This function is a primitive library routine used by optimized F# code and should not be used directly", 1204, IsHidden=true)>]
val inline FSharpEqualityComparer_ER_Equals : x:'T -> y:'T -> bool

/// <summary>A primitive entry point used by the F# compiler for optimization purposes.</summary>
[<CompilerMessage("This function is a primitive library routine used by optimized F# code and should not be used directly", 1204, IsHidden=true)>]
val inline FSharpEqualityComparer_PER_Equals : x:'T -> y:'T -> bool

/// <summary>A primitive entry point used by the F# compiler for optimization purposes.</summary>
[<CompilerMessage("This function is a primitive library routine used by optimized F# code and should not be used directly", 1204, IsHidden=true)>]
val inline FSharpEqualityComparer_GetHashCode : x:'T -> int

/// <summary>A primitive entry point used by the F# compiler for optimization purposes.</summary>
[<CompilerMessage("This function is a primitive library routine used by optimized F# code and should not be used directly", 1204, IsHidden=true)>]
val PhysicalHashIntrinsic : input:'T -> int when 'T : not struct
Expand Down
Loading