diff --git a/src/fsharp/FSharp.Core/FSharp.Core.fsproj b/src/fsharp/FSharp.Core/FSharp.Core.fsproj
index f7267fe0d84..305b1f30da2 100644
--- a/src/fsharp/FSharp.Core/FSharp.Core.fsproj
+++ b/src/fsharp/FSharp.Core/FSharp.Core.fsproj
@@ -108,6 +108,9 @@
Collections/array3.fs
+
+ Collections/mapsetcmp.fs
+
Collections/map.fsi
diff --git a/src/fsharp/FSharp.Core/map.fs b/src/fsharp/FSharp.Core/map.fs
index c0f28b9715a..1345dcee9b8 100644
--- a/src/fsharp/FSharp.Core/map.fs
+++ b/src/fsharp/FSharp.Core/map.fs
@@ -1,45 +1,51 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
-
namespace Microsoft.FSharp.Collections
open System
open System.Collections.Generic
open System.Diagnostics
+open System.Runtime.CompilerServices
open System.Text
open Microsoft.FSharp.Core
open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
[]
[]
-type internal MapTree<'Key, 'Value>(k: 'Key, v: 'Value) =
+type internal MapTree<'Key, 'Value>(k: 'Key, v: 'Value, h: int) =
+ member _.Height = h
member _.Key = k
member _.Value = v
-
+ new(k: 'Key, v: 'Value) = MapTree(k,v,1)
+
[]
[]
[]
type internal MapTreeNode<'Key, 'Value>(k:'Key, v:'Value, left:MapTree<'Key, 'Value>, right: MapTree<'Key, 'Value>, h: int) =
- inherit MapTree<'Key,'Value>(k, v)
-
+ inherit MapTree<'Key,'Value>(k, v, h)
member _.Left = left
member _.Right = right
- member _.Height = h
-
+
[]
module MapTree =
+ open MapSetDefaultComparison
let empty = null
-
+
let inline isEmpty (m:MapTree<'Key, 'Value>) = isNull m
+ let inline private asNode(value:MapTree<'Key,'Value>) : MapTreeNode<'Key,'Value> =
+ value :?> MapTreeNode<'Key,'Value>
+
let rec sizeAux acc (m:MapTree<'Key, 'Value>) =
if isEmpty m then
acc
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn -> sizeAux (sizeAux (acc+1) mn.Left) mn.Right
- | _ -> acc + 1
-
+ if m.Height = 1 then
+ acc + 1
+ else
+ let mn = asNode m
+ sizeAux (sizeAux (acc+1) mn.Left) mn.Right
+
let size x = sizeAux 0 x
#if TRACE_SETS_AND_MAPS
@@ -66,11 +72,11 @@ module MapTree =
(totalSizeOnMapLookup / float numLookups))
System.Console.WriteLine("#largestMapSize = {0}, largestMapStackTrace = {1}", largestMapSize, largestMapStackTrace)
- let MapTree n =
+ let MapTree (k,v) =
report()
numOnes <- numOnes + 1
totalSizeOnNodeCreation <- totalSizeOnNodeCreation + 1.0
- MapTree n
+ MapTree (k,v)
let MapTreeNode (x, l, v, r, h) =
report()
@@ -82,10 +88,7 @@ module MapTree =
let inline height (m: MapTree<'Key, 'Value>) =
if isEmpty m then 0
- else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn -> mn.Height
- | _ -> 1
+ else m.Height
[]
let tolerance = 2
@@ -98,9 +101,6 @@ module MapTree =
MapTree(k,v)
else
MapTreeNode(k,v,l,r,m+1) :> MapTree<'Key, 'Value> // new map is higher by 1 than the highest
-
- let inline private asNode(value:MapTree<'Key,'Value>) : MapTreeNode<'Key,'Value> =
- value :?> MapTreeNode<'Key,'Value>
let rebalance t1 (k: 'Key) (v: 'Value) t2 : MapTree<'Key, 'Value> =
let t1h = height t1
@@ -125,127 +125,120 @@ module MapTree =
mk t1'.Left t1'.Key t1'.Value (mk t1'.Right k v t2)
else mk t1 k v t2
- let rec add (comparer: IComparer<'Key>) k (v: 'Value) (m: MapTree<'Key, 'Value>) : MapTree<'Key, 'Value> =
+ let rec add k (v: 'Value) (m: MapTree<'Key, 'Value>) : MapTree<'Key, 'Value> =
if isEmpty m then MapTree(k,v)
else
- let c = comparer.Compare(k,m.Key)
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
- if c < 0 then rebalance (add comparer k v mn.Left) mn.Key mn.Value mn.Right
- elif c = 0 then MapTreeNode(k,v,mn.Left,mn.Right,mn.Height) :> MapTree<'Key, 'Value>
- else rebalance mn.Left mn.Key mn.Value (add comparer k v mn.Right)
- | _ ->
+ let c = cmp k m.Key
+ if m.Height = 1 then
if c < 0 then MapTreeNode (k,v,empty,m,2) :> MapTree<'Key, 'Value>
elif c = 0 then MapTree(k,v)
else MapTreeNode (k,v,m,empty,2) :> MapTree<'Key, 'Value>
-
- let rec tryGetValue (comparer: IComparer<'Key>) k (v: byref<'Value>) (m: MapTree<'Key, 'Value>) =
+ else
+ let mn = asNode m
+ if c < 0 then rebalance (add k v mn.Left) mn.Key mn.Value mn.Right
+ elif c = 0 then MapTreeNode(k,v,mn.Left,mn.Right,mn.Height) :> MapTree<'Key, 'Value>
+ else rebalance mn.Left mn.Key mn.Value (add k v mn.Right)
+
+ let rec tryGetValue k (v: byref<'Value>) (m: MapTree<'Key, 'Value>) =
if isEmpty m then false
else
- let c = comparer.Compare(k, m.Key)
+ let c = cmp k m.Key
if c = 0 then v <- m.Value; true
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
- tryGetValue comparer k &v (if c < 0 then mn.Left else mn.Right)
- | _ -> false
-
- let find (comparer: IComparer<'Key>) k (m: MapTree<'Key, 'Value>) =
+ if m.Height = 1 then false
+ else
+ let mn = asNode m
+ tryGetValue k &v (if c < 0 then mn.Left else mn.Right)
+
+ []
+ let throwKeyNotFound() = raise (KeyNotFoundException())
+
+ []
+ let find k (m: MapTree<'Key, 'Value>) =
let mutable v = Unchecked.defaultof<'Value>
- if tryGetValue comparer k &v m then
+ if tryGetValue k &v m then
v
else
- raise (KeyNotFoundException())
+ throwKeyNotFound()
- let tryFind (comparer: IComparer<'Key>) k (m: MapTree<'Key, 'Value>) =
+ let tryFind k (m: MapTree<'Key, 'Value>) =
let mutable v = Unchecked.defaultof<'Value>
- if tryGetValue comparer k &v m then
+ if tryGetValue k &v m then
Some v
else
None
- let partition1 (comparer: IComparer<'Key>) (f: OptimizedClosures.FSharpFunc<_, _, _>) k v (acc1, acc2) =
- if f.Invoke (k, v) then (add comparer k v acc1, acc2) else (acc1, add comparer k v acc2)
+ let partition1 (f: OptimizedClosures.FSharpFunc<_, _, _>) k v (acc1, acc2) =
+ if f.Invoke (k, v) then (add k v acc1, acc2) else (acc1, add k v acc2)
- let rec partitionAux (comparer: IComparer<'Key>) (f: OptimizedClosures.FSharpFunc<_, _, _>) (m: MapTree<'Key, 'Value>) acc =
+ let rec partitionAux (f: OptimizedClosures.FSharpFunc<_, _, _>) (m: MapTree<'Key, 'Value>) acc =
if isEmpty m then acc
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
- let acc = partitionAux comparer f mn.Right acc
- let acc = partition1 comparer f mn.Key mn.Value acc
- partitionAux comparer f mn.Left acc
- | _ -> partition1 comparer f m.Key m.Value acc
-
- let partition (comparer: IComparer<'Key>) f m =
- partitionAux comparer (OptimizedClosures.FSharpFunc<_, _, _>.Adapt f) m (empty, empty)
+ if m.Height = 1 then
+ partition1 f m.Key m.Value acc
+ else
+ let mn = asNode m
+ let acc = partitionAux f mn.Right acc
+ let acc = partition1 f mn.Key mn.Value acc
+ partitionAux f mn.Left acc
+
+ let partition f m =
+ partitionAux (OptimizedClosures.FSharpFunc<_, _, _>.Adapt f) m (empty, empty)
- let filter1 (comparer: IComparer<'Key>) (f: OptimizedClosures.FSharpFunc<_, _, _>) k v acc =
- if f.Invoke (k, v) then add comparer k v acc else acc
+ let filter1 (f: OptimizedClosures.FSharpFunc<_, _, _>) k v acc =
+ if f.Invoke (k, v) then add k v acc else acc
- let rec filterAux (comparer: IComparer<'Key>) (f: OptimizedClosures.FSharpFunc<_, _, _>) (m: MapTree<'Key, 'Value>) acc =
+ let rec filterAux (f: OptimizedClosures.FSharpFunc<_, _, _>) (m: MapTree<'Key, 'Value>) acc =
if isEmpty m then acc
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
- let acc = filterAux comparer f mn.Left acc
- let acc = filter1 comparer f mn.Key mn.Value acc
- filterAux comparer f mn.Right acc
- | _ -> filter1 comparer f m.Key m.Value acc
+ if m.Height = 1 then
+ filter1 f m.Key m.Value acc
+ else
+ let mn = asNode m
+ let acc = filterAux f mn.Left acc
+ let acc = filter1 f mn.Key mn.Value acc
+ filterAux f mn.Right acc
+
- let filter (comparer: IComparer<'Key>) f m =
- filterAux comparer (OptimizedClosures.FSharpFunc<_, _, _>.Adapt f) m empty
+ let filter f m =
+ filterAux (OptimizedClosures.FSharpFunc<_, _, _>.Adapt f) m empty
let rec spliceOutSuccessor (m: MapTree<'Key, 'Value>) =
if isEmpty m then failwith "internal error: Map.spliceOutSuccessor"
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
+ if m.Height = 1 then
+ m.Key, m.Value, empty
+ else
+ let mn = asNode m
if isEmpty mn.Left then mn.Key, mn.Value, mn.Right
else let k3, v3, l' = spliceOutSuccessor mn.Left in k3, v3, mk l' mn.Key mn.Value mn.Right
- | _ -> m.Key, m.Value, empty
- let rec remove (comparer: IComparer<'Key>) k (m: MapTree<'Key, 'Value>) =
+ let rec remove k (m: MapTree<'Key, 'Value>) =
if isEmpty m then empty
else
- let c = comparer.Compare(k, m.Key)
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
- if c < 0 then rebalance (remove comparer k mn.Left) mn.Key mn.Value mn.Right
+ let c = cmp k m.Key
+ if m.Height = 1 then
+ if c = 0 then empty else m
+ else
+ let mn = asNode m
+ if c < 0 then rebalance (remove k mn.Left) mn.Key mn.Value mn.Right
elif c = 0 then
if isEmpty mn.Left then mn.Right
elif isEmpty mn.Right then mn.Left
else
let sk, sv, r' = spliceOutSuccessor mn.Right
mk mn.Left sk sv r'
- else rebalance mn.Left mn.Key mn.Value (remove comparer k mn.Right)
- | _ ->
- if c = 0 then empty else m
+ else rebalance mn.Left mn.Key mn.Value (remove k mn.Right)
+
- let rec change (comparer: IComparer<'Key>) k (u: 'Value option -> 'Value option) (m: MapTree<'Key, 'Value>) : MapTree<'Key,'Value> =
+ let rec change k (u: 'Value option -> 'Value option) (m: MapTree<'Key, 'Value>) : MapTree<'Key,'Value> =
if isEmpty m then
match u None with
| None -> m
| Some v -> MapTree (k, v)
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
- let c = comparer.Compare(k, mn.Key)
- if c < 0 then
- rebalance (change comparer k u mn.Left) mn.Key mn.Value mn.Right
- elif c = 0 then
- match u (Some mn.Value) with
- | None ->
- if isEmpty mn.Left then mn.Right
- elif isEmpty mn.Right then mn.Left
- else
- let sk, sv, r' = spliceOutSuccessor mn.Right
- mk mn.Left sk sv r'
- | Some v -> MapTreeNode (k, v, mn.Left, mn.Right, mn.Height) :> MapTree<'Key,'Value>
- else
- rebalance mn.Left mn.Key mn.Value (change comparer k u mn.Right)
- | _ ->
- let c = comparer.Compare(k, m.Key)
+ if m.Height = 1 then
+ let c = cmp k m.Key
if c < 0 then
match u None with
| None -> m
@@ -258,23 +251,44 @@ module MapTree =
match u None with
| None -> m
| Some v -> MapTreeNode (k, v, m, empty, 2) :> MapTree<'Key,'Value>
+ else
+ let mn = asNode m
+ let c = cmp k mn.Key
+ if c < 0 then
+ rebalance (change k u mn.Left) mn.Key mn.Value mn.Right
+ elif c = 0 then
+ match u (Some mn.Value) with
+ | None ->
+ if isEmpty mn.Left then mn.Right
+ elif isEmpty mn.Right then mn.Left
+ else
+ let sk, sv, r' = spliceOutSuccessor mn.Right
+ mk mn.Left sk sv r'
+ | Some v -> MapTreeNode (k, v, mn.Left, mn.Right, mn.Height) :> MapTree<'Key,'Value>
+ else
+ rebalance mn.Left mn.Key mn.Value (change k u mn.Right)
- let rec mem (comparer: IComparer<'Key>) k (m: MapTree<'Key, 'Value>) =
+ let rec mem k (m: MapTree<'Key, 'Value>) =
if isEmpty m then false
else
- let c = comparer.Compare(k, m.Key)
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
- if c < 0 then mem comparer k mn.Left
- else (c = 0 || mem comparer k mn.Right)
- | _ -> c = 0
+ let c = cmp k m.Key
+ if m.Height = 1 then
+ c = 0
+ else
+ let mn = asNode m
+ if c < 0 then mem k mn.Left
+ else (c = 0 || mem k mn.Right)
+
let rec iterOpt (f: OptimizedClosures.FSharpFunc<_, _, _>) (m: MapTree<'Key, 'Value>) =
if isEmpty m then ()
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn -> iterOpt f mn.Left; f.Invoke (mn.Key, mn.Value); iterOpt f mn.Right
- | _ -> f.Invoke (m.Key, m.Value)
+ if m.Height = 1 then
+ f.Invoke (m.Key, m.Value)
+ else
+ let mn = asNode m
+ iterOpt f mn.Left; f.Invoke (mn.Key, mn.Value); iterOpt f mn.Right
+
let iter f m =
iterOpt (OptimizedClosures.FSharpFunc<_, _, _>.Adapt f) m
@@ -282,8 +296,10 @@ module MapTree =
let rec tryPickOpt (f: OptimizedClosures.FSharpFunc<_, _, _>) (m: MapTree<'Key, 'Value>) =
if isEmpty m then None
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
+ if m.Height = 1 then
+ f.Invoke (m.Key, m.Value)
+ else
+ let mn = asNode m
match tryPickOpt f mn.Left with
| Some _ as res -> res
| None ->
@@ -291,7 +307,7 @@ module MapTree =
| Some _ as res -> res
| None ->
tryPickOpt f mn.Right
- | _ -> f.Invoke (m.Key, m.Value)
+
let tryPick f m =
tryPickOpt (OptimizedClosures.FSharpFunc<_, _, _>.Adapt f) m
@@ -299,9 +315,12 @@ module MapTree =
let rec existsOpt (f: OptimizedClosures.FSharpFunc<_, _, _>) (m: MapTree<'Key, 'Value>) =
if isEmpty m then false
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn -> existsOpt f mn.Left || f.Invoke (mn.Key, mn.Value) || existsOpt f mn.Right
- | _ -> f.Invoke (m.Key, m.Value)
+ if m.Height = 1 then
+ f.Invoke (m.Key, m.Value)
+ else
+ let mn = asNode m
+ existsOpt f mn.Left || f.Invoke (mn.Key, mn.Value) || existsOpt f mn.Right
+
let exists f m =
existsOpt (OptimizedClosures.FSharpFunc<_, _, _>.Adapt f) m
@@ -309,9 +328,12 @@ module MapTree =
let rec forallOpt (f: OptimizedClosures.FSharpFunc<_, _, _>) (m: MapTree<'Key, 'Value>) =
if isEmpty m then true
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn -> forallOpt f mn.Left && f.Invoke (mn.Key, mn.Value) && forallOpt f mn.Right
- | _ -> f.Invoke (m.Key, m.Value)
+ if m.Height = 1 then
+ f.Invoke (m.Key, m.Value)
+ else
+ let mn = asNode m
+ forallOpt f mn.Left && f.Invoke (mn.Key, mn.Value) && forallOpt f mn.Right
+
let forall f m =
@@ -320,24 +342,27 @@ module MapTree =
let rec map (f:'Value -> 'Result) (m: MapTree<'Key, 'Value>) : MapTree<'Key, 'Result> =
if isEmpty m then empty
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
+ if m.Height = 1 then
+ MapTree (m.Key, f m.Value)
+ else
+ let mn = asNode m
let l2 = map f mn.Left
let v2 = f mn.Value
let r2 = map f mn.Right
MapTreeNode (mn.Key, v2, l2, r2, mn.Height) :> MapTree<'Key, 'Result>
- | _ -> MapTree (m.Key, f m.Value)
let rec mapiOpt (f: OptimizedClosures.FSharpFunc<'Key, 'Value, 'Result>) (m: MapTree<'Key, 'Value>) =
if isEmpty m then empty
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
+ if m.Height = 1 then
+ MapTree (m.Key, f.Invoke (m.Key, m.Value))
+ else
+ let mn = asNode m
let l2 = mapiOpt f mn.Left
let v2 = f.Invoke (mn.Key, mn.Value)
let r2 = mapiOpt f mn.Right
MapTreeNode (mn.Key, v2, l2, r2, mn.Height) :> MapTree<'Key, 'Result>
- | _ -> MapTree (m.Key, f.Invoke (m.Key, m.Value))
+
let mapi f m =
mapiOpt (OptimizedClosures.FSharpFunc<_, _, _>.Adapt f) m
@@ -345,12 +370,14 @@ module MapTree =
let rec foldBackOpt (f: OptimizedClosures.FSharpFunc<_, _, _, _>) (m: MapTree<'Key, 'Value>) x =
if isEmpty m then x
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
+ if m.Height = 1 then
+ f.Invoke (m.Key, m.Value, x)
+ else
+ let mn = asNode m
let x = foldBackOpt f mn.Right x
let x = f.Invoke (mn.Key, mn.Value, x)
foldBackOpt f mn.Left x
- | _ -> f.Invoke (m.Key, m.Value, x)
+
let foldBack f m x =
foldBackOpt (OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt f) m x
@@ -358,73 +385,77 @@ module MapTree =
let rec foldOpt (f: OptimizedClosures.FSharpFunc<_, _, _, _>) x (m: MapTree<'Key, 'Value>) =
if isEmpty m then x
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
+ if m.Height = 1 then
+ f.Invoke (x, m.Key, m.Value)
+ else
+ let mn = asNode m
let x = foldOpt f x mn.Left
let x = f.Invoke (x, mn.Key, mn.Value)
foldOpt f x mn.Right
- | _ -> f.Invoke (x, m.Key, m.Value)
let fold f x m =
foldOpt (OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt f) x m
- let foldSectionOpt (comparer: IComparer<'Key>) lo hi (f: OptimizedClosures.FSharpFunc<_, _, _, _>) (m: MapTree<'Key, 'Value>) x =
+ let foldSectionOpt lo hi (f: OptimizedClosures.FSharpFunc<_, _, _, _>) (m: MapTree<'Key, 'Value>) x =
let rec foldFromTo (f: OptimizedClosures.FSharpFunc<_, _, _, _>) (m: MapTree<'Key, 'Value>) x =
if isEmpty m then x
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn ->
- let cLoKey = comparer.Compare(lo, mn.Key)
- let cKeyHi = comparer.Compare(mn.Key, hi)
+ if m.Height = 1 then
+ let cLoKey = cmp lo m.Key
+ let cKeyHi = cmp m.Key hi
+ let x = if cLoKey <= 0 && cKeyHi <= 0 then f.Invoke (m.Key, m.Value, x) else x
+ x
+ else
+ let mn = asNode m
+ let cLoKey = cmp lo mn.Key
+ let cKeyHi = cmp mn.Key hi
let x = if cLoKey < 0 then foldFromTo f mn.Left x else x
let x = if cLoKey <= 0 && cKeyHi <= 0 then f.Invoke (mn.Key, mn.Value, x) else x
let x = if cKeyHi < 0 then foldFromTo f mn.Right x else x
x
- | _ ->
- let cLoKey = comparer.Compare(lo, m.Key)
- let cKeyHi = comparer.Compare(m.Key, hi)
- let x = if cLoKey <= 0 && cKeyHi <= 0 then f.Invoke (m.Key, m.Value, x) else x
- x
- if comparer.Compare(lo, hi) = 1 then x else foldFromTo f m x
+ if cmp lo hi = 1 then x else foldFromTo f m x
- let foldSection (comparer: IComparer<'Key>) lo hi f m x =
- foldSectionOpt comparer lo hi (OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt f) m x
+ let foldSection lo hi f m x =
+ foldSectionOpt lo hi (OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt f) m x
let toList (m: MapTree<'Key, 'Value>) =
let rec loop (m: MapTree<'Key, 'Value>) acc =
if isEmpty m then acc
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn -> loop mn.Left ((mn.Key, mn.Value) :: loop mn.Right acc)
- | _ -> (m.Key, m.Value) :: acc
+ if m.Height = 1 then
+ (m.Key, m.Value) :: acc
+ else
+ let mn = asNode m
+ loop mn.Left ((mn.Key, mn.Value) :: loop mn.Right acc)
+
loop m []
let toArray m =
m |> toList |> Array.ofList
- let ofList comparer l =
- List.fold (fun acc (k, v) -> add comparer k v acc) empty l
+ let ofList l =
+ List.fold (fun acc (k, v) -> add k v acc) empty l
- let rec mkFromEnumerator comparer acc (e : IEnumerator<_>) =
+ let rec mkFromEnumerator acc (e : IEnumerator<_>) =
if e.MoveNext() then
let (x, y) = e.Current
- mkFromEnumerator comparer (add comparer x y acc) e
+ mkFromEnumerator (add x y acc) e
else acc
- let ofArray comparer (arr : array<'Key * 'Value>) =
+ let ofArray (arr : array<'Key * 'Value>) =
let mutable res = empty
for (x, y) in arr do
- res <- add comparer x y res
+ res <- add x y res
res
- let ofSeq comparer (c : seq<'Key * 'T>) =
+ let ofSeq (c : seq<'Key * 'T>) =
match c with
- | :? array<'Key * 'T> as xs -> ofArray comparer xs
- | :? list<'Key * 'T> as xs -> ofList comparer xs
+ | :? array<'Key * 'T> as xs -> ofArray xs
+ | :? list<'Key * 'T> as xs -> ofList xs
| _ ->
use ie = c.GetEnumerator()
- mkFromEnumerator comparer empty ie
+ mkFromEnumerator empty ie
let copyToArray m (arr: _[]) i =
let mutable j = i
@@ -448,9 +479,11 @@ module MapTree =
| m :: rest ->
if isEmpty m then collapseLHS rest
else
- match m with
- | :? MapTreeNode<'Key, 'Value> as mn -> collapseLHS (mn.Left :: MapTree (mn.Key, mn.Value) :: mn.Right :: rest)
- | _ -> stack
+ if m.Height = 1 then
+ stack
+ else
+ let mn = asNode m
+ collapseLHS (mn.Left :: MapTree (mn.Key, mn.Value) :: mn.Right :: rest)
let mkIterator m =
{ stack = collapseLHS [m]; started = false }
@@ -460,15 +493,20 @@ module MapTree =
let alreadyFinished() =
raise (InvalidOperationException(SR.GetString(SR.enumerationAlreadyFinished)))
+
+ let unexpectedStackForCurrent() =
+ failwith "Please report error: Map iterator, unexpected stack for current"
+
+ let unexpectedStackForMoveNext() =
+ failwith "Please report error: Map iterator, unexpected stack for moveNext"
let current i =
if i.started then
match i.stack with
| [] -> alreadyFinished()
| m :: _ ->
- match m with
- | :? MapTreeNode<'Key, 'Value> -> failwith "Please report error: Map iterator, unexpected stack for current"
- | _ -> new KeyValuePair<_, _>(m.Key, m.Value)
+ if m.Height = 1 then KeyValuePair<_, _>(m.Key, m.Value)
+ else unexpectedStackForCurrent()
else
notStarted()
@@ -477,11 +515,10 @@ module MapTree =
match i.stack with
| [] -> false
| m :: rest ->
- match m with
- | :? MapTreeNode<'Key, 'Value> -> failwith "Please report error: Map iterator, unexpected stack for moveNext"
- | _ ->
+ if m.Height = 1 then
i.stack <- collapseLHS rest
not i.stack.IsEmpty
+ else unexpectedStackForMoveNext()
else
i.started <- true (* The first call to MoveNext "starts" the enumeration. *)
not i.stack.IsEmpty
@@ -504,12 +541,8 @@ module MapTree =
[]
[]
[]
-type Map<[]'Key, []'Value when 'Key : comparison >(comparer: IComparer<'Key>, tree: MapTree<'Key, 'Value>) =
+type Map<[]'Key, []'Value when 'Key : comparison >(tree: MapTree<'Key, 'Value>) =
- []
- // This type is logically immutable. This field is only mutated during deserialization.
- let mutable comparer = comparer
-
[]
// This type is logically immutable. This field is only mutated during deserialization.
let mutable tree = tree
@@ -523,8 +556,7 @@ type Map<[]'Key, [
- new Map<'Key, 'Value>(comparer, MapTree.empty)
+ new Map<'Key, 'Value>(MapTree.empty : MapTree<'Key, 'Value>)
[]
member _.OnSerializing(context: System.Runtime.Serialization.StreamingContext) =
@@ -539,23 +571,20 @@ type Map<[]'Key, []
member _.OnDeserialized(context: System.Runtime.Serialization.StreamingContext) =
ignore context
- comparer <- LanguagePrimitives.FastGenericComparer<'Key>
- tree <- serializedData |> Array.map (fun kvp -> kvp.Key, kvp.Value) |> MapTree.ofArray comparer
+ tree <- serializedData |> Array.map (fun kvp -> kvp.Key, kvp.Value) |> MapTree.ofArray
serializedData <- null
static member Empty : Map<'Key, 'Value> =
empty
static member Create(ie : IEnumerable<_>) : Map<'Key, 'Value> =
- let comparer = LanguagePrimitives.FastGenericComparer<'Key>
- new Map<_, _>(comparer, MapTree.ofSeq comparer ie)
+ Map<_, _>(MapTree.ofSeq ie)
new (elements : seq<_>) =
- let comparer = LanguagePrimitives.FastGenericComparer<'Key>
- new Map<_, _>(comparer, MapTree.ofSeq comparer elements)
+ Map<_, _>(MapTree.ofSeq elements)
[]
- member internal m.Comparer = comparer
+ member internal m.Comparer = LanguagePrimitives.FastGenericComparer
//[]
member internal m.Tree = tree
@@ -570,10 +599,10 @@ type Map<[]'Key, [(comparer, MapTree.add comparer key value tree)
+ new Map<'Key, 'Value>(MapTree.add key value tree)
member m.Change(key, f) : Map<'Key, 'Value> =
- new Map<'Key, 'Value>(comparer, MapTree.change comparer key f tree)
+ new Map<'Key, 'Value>(MapTree.change key f tree)
[]
member m.IsEmpty = MapTree.isEmpty tree
@@ -585,7 +614,7 @@ type Map<[]'Key, []'Key, [(comparer, MapTree.filter comparer predicate tree)
+ new Map<'Key, 'Value>(MapTree.filter predicate tree)
member m.ForAll predicate =
MapTree.forall predicate tree
@@ -603,20 +632,20 @@ type Map<[]'Key, ['Result) =
- new Map<'Key, 'Result>(comparer, MapTree.map f tree)
+ new Map<'Key, 'Result>(MapTree.map f tree)
member m.Map f =
- new Map<'Key, 'b>(comparer, MapTree.mapi f tree)
+ new Map<'Key, 'b>(MapTree.mapi f tree)
member m.Partition predicate : Map<'Key, 'Value> * Map<'Key, 'Value> =
- let r1, r2 = MapTree.partition comparer predicate tree
- new Map<'Key, 'Value>(comparer, r1), new Map<'Key, 'Value>(comparer, r2)
+ let r1, r2 = MapTree.partition predicate tree
+ new Map<'Key, 'Value>(r1), new Map<'Key, 'Value>(r2)
member m.Count =
MapTree.size tree
@@ -627,13 +656,13 @@ type Map<[]'Key, [(comparer, MapTree.remove comparer key tree)
+ new Map<'Key, 'Value>(MapTree.remove key tree)
member m.TryGetValue(key, [] value: byref<'Value>) =
- MapTree.tryGetValue comparer key &value tree
+ MapTree.tryGetValue key &value tree
member m.TryFind key =
#if TRACE_SETS_AND_MAPS
@@ -641,7 +670,7 @@ type Map<[]'Key, []'Key, [ =
- let comparer = LanguagePrimitives.FastGenericComparer<'Key>
- new Map<_, _>(comparer, MapTree.ofList comparer l)
+ Map<_, _>(MapTree.ofList l)
member this.ComputeHashCode() =
let combineHash x y = (x <<< 1) + y + 631
@@ -724,7 +752,7 @@ type Map<[]'Key, [ as m2->
Seq.compareWith
(fun (kvp1 : KeyValuePair<_, _>) (kvp2 : KeyValuePair<_, _>)->
- let c = comparer.Compare(kvp1.Key, kvp2.Key) in
+ let c = MapSetDefaultComparison.cmp kvp1.Key kvp2.Key in
if c <> 0 then c else Unchecked.compare kvp1.Value kvp2.Value)
m m2
| _ ->
@@ -877,8 +905,7 @@ module Map =
[]
let ofArray (elements: ('Key * 'Value) array) =
- let comparer = LanguagePrimitives.FastGenericComparer<'Key>
- new Map<_, _>(comparer, MapTree.ofArray comparer elements)
+ Map<_, _>(MapTree.ofArray elements)
[]
let toList (table: Map<_, _>) =
diff --git a/src/fsharp/FSharp.Core/mapsetcmp.fs b/src/fsharp/FSharp.Core/mapsetcmp.fs
new file mode 100644
index 00000000000..d05f73ab337
--- /dev/null
+++ b/src/fsharp/FSharp.Core/mapsetcmp.fs
@@ -0,0 +1,122 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+namespace Microsoft.FSharp.Collections
+
+open System
+open System.Collections
+open System.Numerics
+open System.Reflection
+open System.Runtime.CompilerServices
+open Microsoft.FSharp.Core
+open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
+
+module internal MapSetDefaultComparison =
+ type CompareHelper<'T when 'T : comparison>() =
+ static let c = LanguagePrimitives.FastGenericComparer
+
+ // A constrained call to IComparable<'T>.CompareTo
+ static member private CompareCG<'U when 'U :> IComparable<'U>>(l:'U, r:'U):int = l.CompareTo(r)
+
+ // A call to IComparable.CompareTo
+ static member private CompareC<'U when 'U :> IComparable>(l:'U, r:'U):int = l.CompareTo(r)
+
+ static member val CompareToDlg : Func<'T,'T,int> =
+ let dlg =
+ let ty = typeof<'T>
+ try
+ let normalCmp =
+ not (typeof.IsAssignableFrom(ty))
+ && isNull (Attribute.GetCustomAttribute(ty, typeof))
+ && isNull (Attribute.GetCustomAttribute(ty, typeof))
+ && not (ty.IsArray)
+
+ // See #816, IComparable<'T> actually does not satisfy comparison constraint, but it should be preferred
+ if typeof>.IsAssignableFrom(ty) then
+ let m =
+ typeof>.GetMethod("CompareCG", BindingFlags.NonPublic ||| BindingFlags.Static)
+ .MakeGenericMethod([|ty|])
+ Delegate.CreateDelegate(typeof>, m) :?> Func<'T,'T,int>
+ elif typeof.IsAssignableFrom(ty) && normalCmp then
+ let m =
+ typeof>.GetMethod("CompareC", BindingFlags.NonPublic ||| BindingFlags.Static)
+ .MakeGenericMethod([|typeof<'T>|])
+ Delegate.CreateDelegate(typeof>, m) :?> Func<'T,'T,int>
+ else null
+ with _ -> null
+ dlg
+ with get
+
+ // If backed by static readonly field that will be JIT-time constant
+ static member val IsIComparable = not(isNull CompareHelper<'T>.CompareToDlg) with get
+
+ []
+ static member Compare(l:'T, r:'T):int =
+ // Should use IsIComparable when it's backed by static readonly field
+ if isNull CompareHelper<'T>.CompareToDlg then
+ c.Compare(l, r)
+ else
+ CompareHelper<'T>.CompareToDlg.Invoke(l,r)
+
+ // Constructors are not inlined by F#, but JIT could inline them.
+ // This is what we need here, because LanguagePrimitives.FastGenericComparer.Compare
+ // has a .tail prefix that breaks the typeof(T)==typeof(...) JIT optimization in cmp
+ // A struct with a single int field should be lowered by JIT.
+ []
+ []
+ type Comparison<'T when 'T : comparison> =
+ struct
+ val Value: int
+ []
+ new(l:'T,r:'T) = { Value = CompareHelper<'T>.Compare(l, r) }
+ end
+
+ []
+ let cmp<'T when 'T : comparison> (l:'T) (r:'T) : int =
+ // See the pattern explanation: https://github.com/dotnet/runtime/blob/4b8d10154c39b1f56424d4ba2068a3150d90d475/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs#L14
+ // All types that implement IComparable<'T> and are accessible here without additional dependencies should be in the list
+ if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+ else if Type.op_Equality(typeof<'T>, typeof) then
+ unbox(box(l)).ToInt64().CompareTo( (unbox(box(r))).ToInt64())
+ else if Type.op_Equality(typeof<'T>, typeof) then
+ unbox(box(l)).ToUInt64().CompareTo( (unbox(box(r))).ToUInt64())
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+
+ // F# rules for floats
+ else if Type.op_Equality(typeof<'T>, typeof) then
+ let l = unbox(box(l))
+ let r = unbox(box(r))
+ if l < r then (-1)
+ elif l > r then (1)
+ elif l = r then (0)
+ elif r = r then (-1)
+ elif l = l then (1)
+ else 0
+ else if Type.op_Equality(typeof<'T>, typeof) then
+ let l = unbox(box(l))
+ let r = unbox(box(r))
+ if l < r then (-1)
+ elif l > r then (1)
+ elif l = r then (0)
+ elif r = r then (-1)
+ elif l = l then (1)
+ else 0
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+ else if Type.op_Equality(typeof<'T>, typeof) then unbox(box(l)).CompareTo(unbox(box(r)))
+
+ else if Type.op_Equality(typeof<'T>, typeof) then
+ // same as in GenericComparisonFast
+ String.CompareOrdinal(unbox(box(l)),(unbox(box(r))))
+
+ else Comparison(l,r).Value
\ No newline at end of file
diff --git a/src/fsharp/FSharp.Core/set.fs b/src/fsharp/FSharp.Core/set.fs
index 23455cb1d44..29f6af81673 100644
--- a/src/fsharp/FSharp.Core/set.fs
+++ b/src/fsharp/FSharp.Core/set.fs
@@ -16,19 +16,19 @@ open Microsoft.FSharp.Collections
[]
[]
-type internal SetTree<'T>(k: 'T) =
+type internal SetTree<'T>(k: 'T, h: int) =
+ member _.Height = h
member _.Key = k
-
+ new(k: 'T) = SetTree(k,1)
+
[]
[]
[]
type internal SetTreeNode<'T>(v:'T, left:SetTree<'T>, right: SetTree<'T>, h: int) =
- inherit SetTree<'T>(v)
-
+ inherit SetTree<'T>(v,h)
member _.Left = left
member _.Right = right
- member _.Height = h
-
+
[]
module internal SetTree =
@@ -36,13 +36,18 @@ module internal SetTree =
let inline isEmpty (t:SetTree<'T>) = isNull t
+ let inline private asNode(value:SetTree<'T>) : SetTreeNode<'T> =
+ value :?> SetTreeNode<'T>
+
let rec countAux (t:SetTree<'T>) acc =
if isEmpty t then
acc
else
- match t with
- | :? SetTreeNode<'T> as tn -> countAux tn.Left (countAux tn.Right (acc+1))
- | _ -> acc+1
+ if t.Height = 1 then
+ acc + 1
+ else
+ let tn = asNode t
+ countAux tn.Left (countAux tn.Right (acc+1))
let count s = countAux s 0
@@ -84,22 +89,19 @@ module internal SetTree =
let inline height (t:SetTree<'T>) =
if isEmpty t then 0
- else
- match t with
- | :? SetTreeNode<'T> as tn -> tn.Height
- | _ -> 1
+ else t.Height
#if CHECKED
let rec checkInvariant (t:SetTree<'T>) =
// A good sanity check, loss of balance can hit perf
if isEmpty t then true
else
- match t with
- | :? SetTreeNode<'T> as tn ->
+ if t.Height = 1 then true
+ else
+ let tn = asNode t
let h1 = height tn.Left
let h2 = height tn.Right
(-2 <= (h1 - h2) && (h1 - h2) <= 2) && checkInvariant tn.Left && checkInvariant tn.Right
- | _ -> true
#endif
[]
@@ -114,9 +116,6 @@ module internal SetTree =
else
SetTreeNode (k, l, r, m+1) :> SetTree<'T>
- let inline private asNode(value:SetTree<'T>) : SetTreeNode<'T> =
- value :?> SetTreeNode<'T>
-
let rebalance t1 v t2 =
let t1h = height t1
let t2h = height t2
@@ -144,17 +143,16 @@ module internal SetTree =
if isEmpty t then SetTree k
else
let c = comparer.Compare(k, t.Key)
- match t with
- | :? SetTreeNode<'T> as tn ->
- if c < 0 then rebalance (add comparer k tn.Left) tn.Key tn.Right
- elif c = 0 then t
- else rebalance tn.Left tn.Key (add comparer k tn.Right)
- | _ ->
+ if t.Height = 1 then
// nb. no check for rebalance needed for small trees, also be sure to reuse node already allocated
- let c = comparer.Compare(k, t.Key)
if c < 0 then SetTreeNode (k, empty, t, 2) :> SetTree<'T>
elif c = 0 then t
else SetTreeNode (k, t, empty, 2) :> SetTree<'T>
+ else
+ let tn = asNode t
+ if c < 0 then rebalance (add comparer k tn.Left) tn.Key tn.Right
+ elif c = 0 then t
+ else rebalance tn.Left tn.Key (add comparer k tn.Right)
let rec balance comparer (t1:SetTree<'T>) k (t2:SetTree<'T>) =
// Given t1 < k < t2 where t1 and t2 are "balanced",
@@ -163,10 +161,12 @@ module internal SetTree =
if isEmpty t1 then add comparer k t2 // drop t1 = empty
elif isEmpty t2 then add comparer k t1 // drop t2 = empty
else
- match t1 with
- | :? SetTreeNode<'T> as t1n ->
- match t2 with
- | :? SetTreeNode<'T> as t2n ->
+ if t1.Height = 1 then add comparer k (add comparer t1.Key t2)
+ else
+ let t1n = asNode t1
+ if t2.Height = 1 then add comparer k (add comparer t2.Key t1)
+ else
+ let t2n = asNode t2
// Have: (t1l < k1 < t1r) < k < (t2l < k2 < t2r)
// Either (a) h1, h2 differ by at most 2 - no rebalance needed.
// (b) h1 too small, i.e. h1+2 < h2
@@ -182,16 +182,19 @@ module internal SetTree =
else
// case: a, h1 and h2 meet balance requirement
mk t1 k t2
- | _ -> add comparer k (add comparer t2.Key t1)
- | _ -> add comparer k (add comparer t1.Key t2)
let rec split (comparer: IComparer<'T>) pivot (t:SetTree<'T>) =
// Given a pivot and a set t
// Return { x in t s.t. x < pivot }, pivot in t?, { x in t s.t. x > pivot }
if isEmpty t then empty, false, empty
else
- match t with
- | :? SetTreeNode<'T> as tn ->
+ if t.Height = 1 then
+ let c = comparer.Compare(t.Key, pivot)
+ if c < 0 then t, false, empty // singleton under pivot
+ elif c = 0 then empty, true, empty // singleton is pivot
+ else empty, false, t // singleton over pivot
+ else
+ let tn = asNode t
let c = comparer.Compare(pivot, tn.Key)
if c < 0 then // pivot t1
let t11Lo, havePivot, t11Hi = split comparer pivot tn.Left
@@ -201,27 +204,24 @@ module internal SetTree =
else // pivot t2
let t12Lo, havePivot, t12Hi = split comparer pivot tn.Right
balance comparer tn.Left tn.Key t12Lo, havePivot, t12Hi
- | _ ->
- let c = comparer.Compare(t.Key, pivot)
- if c < 0 then t, false, empty // singleton under pivot
- elif c = 0 then empty, true, empty // singleton is pivot
- else empty, false, t // singleton over pivot
let rec spliceOutSuccessor (t:SetTree<'T>) =
if isEmpty t then failwith "internal error: Set.spliceOutSuccessor"
else
- match t with
- | :? SetTreeNode<'T> as tn ->
+ if t.Height = 1 then t.Key, empty
+ else
+ let tn = asNode t
if isEmpty tn.Left then tn.Key, tn.Right
else let k3, l' = spliceOutSuccessor tn.Left in k3, mk l' tn.Key tn.Right
- | _ -> t.Key, empty
let rec remove (comparer: IComparer<'T>) k (t:SetTree<'T>) =
if isEmpty t then t
else
let c = comparer.Compare(k, t.Key)
- match t with
- | :? SetTreeNode<'T> as tn ->
+ if t.Height = 1 then
+ if c = 0 then empty else t
+ else
+ let tn = asNode t
if c < 0 then rebalance (remove comparer k tn.Left) tn.Key tn.Right
elif c = 0 then
if isEmpty tn.Left then tn.Right
@@ -229,63 +229,64 @@ module internal SetTree =
else
let sk, r' = spliceOutSuccessor tn.Right
mk tn.Left sk r'
- else rebalance tn.Left tn.Key (remove comparer k tn.Right)
- | _ ->
- if c = 0 then empty
- else t
+ else rebalance tn.Left tn.Key (remove comparer k tn.Right)
let rec mem (comparer: IComparer<'T>) k (t:SetTree<'T>) =
if isEmpty t then false
else
let c = comparer.Compare(k, t.Key)
- match t with
- | :? SetTreeNode<'T> as tn ->
+ if t.Height = 1 then (c = 0)
+ else
+ let tn = asNode t
if c < 0 then mem comparer k tn.Left
elif c = 0 then true
else mem comparer k tn.Right
- | _ -> (c = 0)
let rec iter f (t:SetTree<'T>) =
if isEmpty t then ()
else
- match t with
- | :? SetTreeNode<'T> as tn -> iter f tn.Left; f tn.Key; iter f tn.Right
- | _ -> f t.Key
+ if t.Height = 1 then f t.Key
+ else
+ let tn = asNode t
+ iter f tn.Left; f tn.Key; iter f tn.Right
let rec foldBackOpt (f:OptimizedClosures.FSharpFunc<_, _, _>) (t:SetTree<'T>) x =
if isEmpty t then x
else
- match t with
- | :? SetTreeNode<'T> as tn -> foldBackOpt f tn.Left (f.Invoke(tn.Key, (foldBackOpt f tn.Right x)))
- | _ -> f.Invoke(t.Key, x)
+ if t.Height = 1 then f.Invoke(t.Key, x)
+ else
+ let tn = asNode t
+ foldBackOpt f tn.Left (f.Invoke(tn.Key, (foldBackOpt f tn.Right x)))
let foldBack f m x = foldBackOpt (OptimizedClosures.FSharpFunc<_, _, _>.Adapt f) m x
let rec foldOpt (f:OptimizedClosures.FSharpFunc<_, _, _>) x (t:SetTree<'T>) =
if isEmpty t then x
else
- match t with
- | :? SetTreeNode<'T> as tn ->
+ if t.Height = 1 then f.Invoke(x, t.Key)
+ else
+ let tn = asNode t
let x = foldOpt f x tn.Left in
let x = f.Invoke(x, tn.Key)
foldOpt f x tn.Right
- | _ -> f.Invoke(x, t.Key)
let fold f x m = foldOpt (OptimizedClosures.FSharpFunc<_, _, _>.Adapt f) x m
let rec forall f (t:SetTree<'T>) =
if isEmpty t then true
else
- match t with
- | :? SetTreeNode<'T> as tn -> f tn.Key && forall f tn.Left && forall f tn.Right
- | _ -> f t.Key
+ if t.Height = 1 then f t.Key
+ else
+ let tn = asNode t
+ f tn.Key && forall f tn.Left && forall f tn.Right
let rec exists f (t:SetTree<'T>) =
if isEmpty t then false
else
- match t with
- | :? SetTreeNode<'T> as tn -> f tn.Key || exists f tn.Left || exists f tn.Right
- | _ -> f t.Key
+ if t.Height = 1 then f t.Key
+ else
+ let tn = asNode t
+ f tn.Key || exists f tn.Left || exists f tn.Right
let subset comparer a b =
forall (fun x -> mem comparer x b) a
@@ -296,11 +297,12 @@ module internal SetTree =
let rec filterAux comparer f (t:SetTree<'T>) acc =
if isEmpty t then acc
else
- match t with
- | :? SetTreeNode<'T> as tn ->
+ if t.Height = 1 then
+ if f t.Key then add comparer t.Key acc else acc
+ else
+ let tn = asNode t
let acc = if f tn.Key then add comparer tn.Key acc else acc
filterAux comparer f tn.Left (filterAux comparer f tn.Right acc)
- | _ -> if f t.Key then add comparer t.Key acc else acc
let filter comparer f s = filterAux comparer f s empty
@@ -309,9 +311,10 @@ module internal SetTree =
else
if isEmpty t then acc
else
- match t with
- | :? SetTreeNode<'T> as tn -> diffAux comparer tn.Left (diffAux comparer tn.Right (remove comparer tn.Key acc))
- | _ -> remove comparer t.Key acc
+ if t.Height = 1 then remove comparer t.Key acc
+ else
+ let tn = asNode t
+ diffAux comparer tn.Left (diffAux comparer tn.Right (remove comparer tn.Key acc))
let diff comparer a b = diffAux comparer b a
@@ -320,10 +323,12 @@ module internal SetTree =
if isEmpty t1 then t2
elif isEmpty t2 then t1
else
- match t1 with
- | :? SetTreeNode<'T> as t1n ->
- match t2 with
- | :? SetTreeNode<'T> as t2n -> // (t1l < k < t1r) AND (t2l < k2 < t2r)
+ if t1.Height = 1 then add comparer t1.Key t2
+ else
+ if t2.Height = 1 then add comparer t2.Key t1
+ else
+ let t1n = asNode t1
+ let t2n = asNode t2 // (t1l < k < t1r) AND (t2l < k2 < t2r)
// Divide and Conquer:
// Suppose t1 is largest.
// Split t2 using pivot k1 into lo and hi.
@@ -334,19 +339,17 @@ module internal SetTree =
else
let lo, _, hi = split comparer t2n.Key t1 in
balance comparer (union comparer t2n.Left lo) t2n.Key (union comparer t2n.Right hi)
- | _ -> add comparer t2.Key t1
- | _ -> add comparer t1.Key t2
let rec intersectionAux comparer b (t:SetTree<'T>) acc =
if isEmpty t then acc
else
- match t with
- | :? SetTreeNode<'T> as tn ->
+ if t.Height = 1 then
+ if mem comparer t.Key b then add comparer t.Key acc else acc
+ else
+ let tn = asNode t
let acc = intersectionAux comparer b tn.Right acc
let acc = if mem comparer tn.Key b then add comparer tn.Key acc else acc
intersectionAux comparer b tn.Left acc
- | _ ->
- if mem comparer t.Key b then add comparer t.Key acc else acc
let intersection comparer a b = intersectionAux comparer b a empty
@@ -355,42 +358,46 @@ module internal SetTree =
let rec partitionAux comparer f (t:SetTree<'T>) acc =
if isEmpty t then acc
else
- match t with
- | :? SetTreeNode<'T> as tn ->
+ if t.Height = 1 then partition1 comparer f t.Key acc
+ else
+ let tn = asNode t
let acc = partitionAux comparer f tn.Right acc
let acc = partition1 comparer f tn.Key acc
partitionAux comparer f tn.Left acc
- | _ -> partition1 comparer f t.Key acc
let partition comparer f s = partitionAux comparer f s (empty, empty)
let rec minimumElementAux (t:SetTree<'T>) n =
if isEmpty t then n
else
- match t with
- | :? SetTreeNode<'T> as tn -> minimumElementAux tn.Left tn.Key
- | _ -> t.Key
+ if t.Height = 1 then t.Key
+ else
+ let tn = asNode t
+ minimumElementAux tn.Left tn.Key
and minimumElementOpt (t:SetTree<'T>) =
if isEmpty t then None
else
- match t with
- | :? SetTreeNode<'T> as tn -> Some(minimumElementAux tn.Left tn.Key)
- | _ -> Some t.Key
+ if t.Height = 1 then Some t.Key
+ else
+ let tn = asNode t
+ Some(minimumElementAux tn.Left tn.Key)
and maximumElementAux (t:SetTree<'T>) n =
if isEmpty t then n
else
- match t with
- | :? SetTreeNode<'T> as tn -> maximumElementAux tn.Right tn.Key
- | _ -> t.Key
+ if t.Height = 1 then t.Key
+ else
+ let tn = asNode t
+ maximumElementAux tn.Right tn.Key
and maximumElementOpt (t:SetTree<'T>) =
if isEmpty t then None
else
- match t with
- | :? SetTreeNode<'T> as tn -> Some(maximumElementAux tn.Right tn.Key)
- | _ -> Some t.Key
+ if t.Height = 1 then Some t.Key
+ else
+ let tn = asNode t
+ Some(maximumElementAux tn.Right tn.Key)
let minimumElement s =
match minimumElementOpt s with
@@ -418,9 +425,10 @@ module internal SetTree =
| x :: rest ->
if isEmpty x then collapseLHS rest
else
- match x with
- | :? SetTreeNode<'T> as xn-> collapseLHS (xn.Left :: SetTree xn.Key :: xn.Right :: rest)
- | _ -> stack
+ if x.Height = 1 then stack
+ else
+ let xn = asNode x
+ collapseLHS (xn.Left :: SetTree xn.Key :: xn.Right :: rest)
let mkIterator s = { stack = collapseLHS [s]; started = false }
@@ -436,16 +444,19 @@ module internal SetTree =
else
notStarted()
+ let unexpectedStackForMoveNext() = failwith "Please report error: Set iterator, unexpected stack for moveNext"
+ let unexpectedstateInSetTreeCompareStacks() = failwith "unexpected state in SetTree.compareStacks"
+
let rec moveNext i =
if i.started then
match i.stack with
| [] -> false
| t :: rest ->
- match t with
- | :? SetTreeNode<'T> -> failwith "Please report error: Set iterator, unexpected stack for moveNext"
- | _ ->
+ if t.Height = 1 then
i.stack <- collapseLHS rest
- not i.stack.IsEmpty
+ not i.stack.IsEmpty
+ else
+ unexpectedStackForMoveNext()
else
i.started <- true; // The first call to MoveNext "starts" the enumeration.
not i.stack.IsEmpty
@@ -466,16 +477,18 @@ module internal SetTree =
let cont() =
match l1, l2 with
| (x1 :: t1), _ when not (isEmpty x1) ->
- match x1 with
- | :? SetTreeNode<'T> as x1n ->
+ if x1.Height = 1 then
+ compareStacks comparer (empty :: SetTree x1.Key :: t1) l2
+ else
+ let x1n = asNode x1
compareStacks comparer (x1n.Left :: (SetTreeNode (x1n.Key, empty, x1n.Right, 0) :> SetTree<'T>) :: t1) l2
- | _ -> compareStacks comparer (empty :: SetTree x1.Key :: t1) l2
| _, (x2 :: t2) when not (isEmpty x2) ->
- match x2 with
- | :? SetTreeNode<'T> as x2n ->
+ if x2.Height = 1 then
+ compareStacks comparer l1 (empty :: SetTree x2.Key :: t2)
+ else
+ let x2n = asNode x2
compareStacks comparer l1 (x2n.Left :: (SetTreeNode (x2n.Key, empty, x2n.Right, 0) :> SetTree<'T> ) :: t2)
- | _ -> compareStacks comparer l1 (empty :: SetTree x2.Key :: t2)
- | _ -> failwith "unexpected state in SetTree.compareStacks"
+ | _ -> unexpectedstateInSetTreeCompareStacks()
match l1, l2 with
| [], [] -> 0
@@ -487,30 +500,30 @@ module internal SetTree =
else cont()
elif isEmpty x2 then cont()
else
- match x1 with
- | :? SetTreeNode<'T> as x1n ->
+ if x1.Height = 1 then
+ if x2.Height = 1 then
+ let c = comparer.Compare(x1.Key, x2.Key)
+ if c <> 0 then c else compareStacks comparer t1 t2
+ else
+ let x2n = asNode x2
+ if isEmpty x2n.Left then
+ let c = comparer.Compare(x1.Key, x2n.Key)
+ if c <> 0 then c else compareStacks comparer (empty :: t1) (x2n.Right :: t2)
+ else cont()
+ else
+ let x1n = asNode x1
if isEmpty x1n.Left then
- match x2 with
- | :? SetTreeNode<'T> as x2n ->
+ if x2.Height = 1 then
+ let c = comparer.Compare(x1n.Key, x2.Key)
+ if c <> 0 then c else compareStacks comparer (x1n.Right :: t1) (empty :: t2)
+ else
+ let x2n = asNode x2
if isEmpty x2n.Left then
let c = comparer.Compare(x1n.Key, x2n.Key)
if c <> 0 then c else compareStacks comparer (x1n.Right :: t1) (x2n.Right :: t2)
else cont()
- | _ ->
- let c = comparer.Compare(x1n.Key, x2.Key)
- if c <> 0 then c else compareStacks comparer (x1n.Right :: t1) (empty :: t2)
else cont()
- | _ ->
- match x2 with
- | :? SetTreeNode<'T> as x2n ->
- if isEmpty x2n.Left then
- let c = comparer.Compare(x1.Key, x2n.Key)
- if c <> 0 then c else compareStacks comparer (empty :: t1) (x2n.Right :: t2)
- else cont()
- | _ ->
- let c = comparer.Compare(x1.Key, x2.Key)
- if c <> 0 then c else compareStacks comparer t1 t2
-
+
let compare comparer (t1:SetTree<'T>) (t2:SetTree<'T>) =
if isEmpty t1 then
if isEmpty t2 then 0
@@ -526,9 +539,10 @@ module internal SetTree =
let rec loop (t':SetTree<'T>) acc =
if isEmpty t' then acc
else
- match t' with
- | :? SetTreeNode<'T> as tn -> loop tn.Left (tn.Key :: loop tn.Right acc)
- | _ -> t'.Key :: acc
+ if t'.Height = 1 then t'.Key :: acc
+ else
+ let tn = asNode t'
+ loop tn.Left (tn.Key :: loop tn.Right acc)
loop t []
let copyToArray s (arr: _[]) i =