From c1c30a81adb79befd1fa95c7e84459a792f9bcba Mon Sep 17 00:00:00 2001
From: Paul Westcott
Date: Sun, 22 Jul 2018 16:14:53 +1000
Subject: [PATCH 1/3] Changed Map.count from O(n) to O(1)
---
src/fsharp/FSharp.Core/map.fs | 46 +++++++++++++++--------------------
1 file changed, 20 insertions(+), 26 deletions(-)
diff --git a/src/fsharp/FSharp.Core/map.fs b/src/fsharp/FSharp.Core/map.fs
index 97c747e4ae..3463f4b6d4 100644
--- a/src/fsharp/FSharp.Core/map.fs
+++ b/src/fsharp/FSharp.Core/map.fs
@@ -13,22 +13,13 @@ namespace Microsoft.FSharp.Collections
type MapTree<'Key,'Value when 'Key : comparison > =
| MapEmpty
| MapOne of 'Key * 'Value
- | MapNode of 'Key * 'Value * MapTree<'Key,'Value> * MapTree<'Key,'Value> * int
+ | MapNode of 'Key * 'Value * MapTree<'Key,'Value> * MapTree<'Key,'Value> * size:int
// REVIEW: performance rumour has it that the data held in MapNode and MapOne should be
// exactly one cache line. It is currently ~7 and 4 words respectively.
[]
module MapTree =
- let rec sizeAux acc m =
- match m with
- | MapEmpty -> acc
- | MapOne _ -> acc + 1
- | MapNode(_,_,l,r,_) -> sizeAux (sizeAux (acc+1) l) r
-
- let size x = sizeAux 0 x
-
-
#if TRACE_SETS_AND_MAPS
let mutable traceCount = 0
let mutable numOnes = 0
@@ -64,10 +55,10 @@ namespace Microsoft.FSharp.Collections
let empty = MapEmpty
- let height = function
+ let size = function
| MapEmpty -> 0
| MapOne _ -> 1
- | MapNode(_,_,_,_,h) -> h
+ | MapNode (size=s) -> s
let isEmpty m =
match m with
@@ -78,37 +69,40 @@ namespace Microsoft.FSharp.Collections
match l,r with
| MapEmpty,MapEmpty -> MapOne(k,v)
| _ ->
- let hl = height l
- let hr = height r
- let m = if hl < hr then hr else hl
- MapNode(k,v,l,r,m+1)
+ let sl = size l
+ let sr = size r
+ MapNode(k,v,l,r,sl+sr+1)
let rebalance t1 k v t2 =
- let t1h = height t1
- let t2h = height t2
- if t2h > t1h + 2 then (* right is heavier than left *)
+ let t1s = size t1
+ let t2s = size t2
+ if (t2s >>> 1) > t1s then (* right is over twice as heavy as left *)
match t2 with
| MapNode(t2k,t2v,t2l,t2r,_) ->
- (* one of the nodes must have height > height t1 + 1 *)
- if height t2l > t1h + 1 then (* balance left: combination *)
+ (* one of the nodes must have size > size t1 *)
+ if size t2l > t1s then (* balance left: combination *)
match t2l with
| MapNode(t2lk,t2lv,t2ll,t2lr,_) ->
mk (mk t1 k v t2ll) t2lk t2lv (mk t2lr t2k t2v t2r)
- | _ -> failwith "rebalance"
+ | MapOne(t2lk,t2lv) ->
+ mk (mk t1 k v empty) t2lk t2lv (mk empty t2k t2v t2r)
+ | MapEmpty -> failwith "rebalance"
else (* rotate left *)
mk (mk t1 k v t2l) t2k t2v t2r
| _ -> failwith "rebalance"
else
- if t1h > t2h + 2 then (* left is heavier than right *)
+ if (t1s >>> 1) > t2s then (* left is over twice as heavy as right *)
match t1 with
| MapNode(t1k,t1v,t1l,t1r,_) ->
- (* one of the nodes must have height > height t2 + 1 *)
- if height t1r > t2h + 1 then
+ (* one of the nodes must have size > size t2 *)
+ if size t1r > t2s then
(* balance right: combination *)
match t1r with
| MapNode(t1rk,t1rv,t1rl,t1rr,_) ->
mk (mk t1l t1k t1v t1rl) t1rk t1rv (mk t1rr k v t2)
- | _ -> failwith "rebalance"
+ | MapOne(t1rk,t1rv) ->
+ mk (mk t1l t1k t1v empty) t1rk t1rv (mk empty k v t2)
+ | MapEmpty -> failwith "rebalance"
else
mk t1l t1k t1v (mk t1r k v t2)
| _ -> failwith "rebalance"
From 63dc9b563ce0efbd49ba6e5d5180748bd6eafb1c Mon Sep 17 00:00:00 2001
From: Paul Westcott
Date: Mon, 23 Jul 2018 19:15:11 +1000
Subject: [PATCH 2/3] Modified Set to use size rather than height
---
src/fsharp/FSharp.Core/set.fs | 104 ++++++++++++++++------------------
1 file changed, 48 insertions(+), 56 deletions(-)
diff --git a/src/fsharp/FSharp.Core/set.fs b/src/fsharp/FSharp.Core/set.fs
index 85c04a2c24..7eaeb8da8c 100644
--- a/src/fsharp/FSharp.Core/set.fs
+++ b/src/fsharp/FSharp.Core/set.fs
@@ -16,9 +16,9 @@ namespace Microsoft.FSharp.Collections
[]
[]
type SetTree<'T> when 'T: comparison =
- | SetEmpty // height = 0
- | SetNode of 'T * SetTree<'T> * SetTree<'T> * int // height = int
- | SetOne of 'T // height = 1
+ | SetEmpty // size = 0
+ | SetNode of 'T * SetTree<'T> * SetTree<'T> * size:int
+ | SetOne of 'T // size = 1
// OPTIMIZATION: store SetNode(k,SetEmpty,SetEmpty,1) ---> SetOne(k)
// REVIEW: performance rumour has it that the data held in SetNode and SetOne should be
// exactly one cache line on typical architectures. They are currently
@@ -27,14 +27,6 @@ namespace Microsoft.FSharp.Collections
[]
module internal SetTree =
- let rec countAux s acc =
- match s with
- | SetNode(_,l,r,_) -> countAux l (countAux r (acc+1))
- | SetOne(_) -> acc+1
- | SetEmpty -> acc
-
- let count s = countAux s 0
-
#if TRACE_SETS_AND_MAPS
let mutable traceCount = 0
let mutable numOnes = 0
@@ -65,16 +57,17 @@ namespace Microsoft.FSharp.Collections
n
#else
let SetOne n = SetTree.SetOne n
- let SetNode (x,l,r,h) = SetTree.SetNode(x,l,r,h)
+ let SetNode (x,l,r,s) = SetTree.SetNode(x,l,r,s)
#endif
-
- let height t =
+ let empty = SetEmpty
+
+ let size t =
match t with
| SetEmpty -> 0
| SetOne _ -> 1
- | SetNode (_,_,_,h) -> h
+ | SetNode (size=s) -> s
#if CHECKED
let rec checkInvariant t =
@@ -88,46 +81,47 @@ namespace Microsoft.FSharp.Collections
(-2 <= (h1 - h2) && (h1 - h2) <= 2) && checkInvariant t1 && checkInvariant t2
#endif
- let tolerance = 2
-
let mk l k r =
match l,r with
| SetEmpty,SetEmpty -> SetOne (k)
| _ ->
- let hl = height l
- let hr = height r
- let m = if hl < hr then hr else hl
- SetNode(k,l,r,m+1)
+ let sl = size l
+ let sr = size r
+ SetNode(k,l,r,sl+sr+1)
let rebalance t1 k t2 =
- let t1h = height t1
- let t2h = height t2
- if t2h > t1h + tolerance then // right is heavier than left
+ let t1s = size t1
+ let t2s = size t2
+ if (t2s >>> 1) > t1s then (* right is over twice as heavy as left *)
match t2 with
| SetNode(t2k,t2l,t2r,_) ->
- // one of the nodes must have height > height t1 + 1
- if height t2l > t1h + 1 then // balance left: combination
- match t2l with
- | SetNode(t2lk,t2ll,t2lr,_) ->
- mk (mk t1 k t2ll) t2lk (mk t2lr t2k t2r)
- | _ -> failwith "rebalance"
- else // rotate left
- mk (mk t1 k t2l) t2k t2r
+ (* one of the nodes must have size > size t1 *)
+ if size t2l > t1s then (* balance left: combination *)
+ match t2l with
+ | SetNode(t2lk,t2ll,t2lr,_) ->
+ mk (mk t1 k t2ll) t2lk (mk t2lr t2k t2r)
+ | SetOne(t2lk) ->
+ mk (mk t1 k empty) t2lk (mk empty t2k t2r)
+ | SetEmpty -> failwith "rebalance"
+ else (* rotate left *)
+ mk (mk t1 k t2l) t2k t2r
| _ -> failwith "rebalance"
else
- if t1h > t2h + tolerance then // left is heavier than right
- match t1 with
- | SetNode(t1k,t1l,t1r,_) ->
- // one of the nodes must have height > height t2 + 1
- if height t1r > t2h + 1 then
- // balance right: combination
- match t1r with
- | SetNode(t1rk,t1rl,t1rr,_) ->
- mk (mk t1l t1k t1rl) t1rk (mk t1rr k t2)
- | _ -> failwith "rebalance"
- else
- mk t1l t1k (mk t1r k t2)
- | _ -> failwith "rebalance"
+ if (t1s >>> 1) > t2s then (* left is over twice as heavy as right *)
+ match t1 with
+ | SetNode(t1k,t1l,t1r,_) ->
+ (* one of the nodes must have size > size t2 *)
+ if size t1r > t2s then
+ (* balance right: combination *)
+ match t1r with
+ | SetNode(t1rk,t1rl,t1rr,_) ->
+ mk (mk t1l t1k t1rl) t1rk (mk t1rr k t2)
+ | SetOne(t1rk) ->
+ mk (mk t1l t1k empty) t1rk (mk empty k t2)
+ | SetEmpty -> failwith "rebalance"
+ else
+ mk t1l t1k (mk t1r k t2)
+ | _ -> failwith "rebalance"
else mk t1 k t2
let rec add (comparer: IComparer<'T>) k t =
@@ -148,22 +142,22 @@ namespace Microsoft.FSharp.Collections
let rec balance comparer t1 k t2 =
// Given t1 < k < t2 where t1 and t2 are "balanced",
// return a balanced tree for .
- // Recall: balance means subtrees heights differ by at most "tolerance"
+ // Recall: balance means subtrees size of trees differ by a factor of 2
match t1,t2 with
| SetEmpty,t2 -> add comparer k t2 // drop t1 = empty
| t1,SetEmpty -> add comparer k t1 // drop t2 = empty
| SetOne k1,t2 -> add comparer k (add comparer k1 t2)
| t1,SetOne k2 -> add comparer k (add comparer k2 t1)
- | SetNode(k1,t11,t12,h1),SetNode(k2,t21,t22,h2) ->
+ | SetNode(k1,t11,t12,s1),SetNode(k2,t21,t22,s2) ->
// Have: (t11 < k1 < t12) < k < (t21 < k2 < t22)
- // Either (a) h1,h2 differ by at most 2 - no rebalance needed.
- // (b) h1 too small, i.e. h1+2 < h2
- // (c) h2 too small, i.e. h2+2 < h1
- if h1+tolerance < h2 then
+ // Either (a) h1,h2 differ by at most a factory of 2 - no rebalance needed.
+ // (b) h1 too small
+ // (c) h2 too small
+ if (s2 >>> 1) > s1 then
// case: b, h1 too small
// push t1 into low side of t2, may increase height by 1 so rebalance
rebalance (balance comparer t1 k t21) k2 t22
- elif h2+tolerance < h1 then
+ elif (s1 >>> 1) > s2 then
// case: c, h2 too small
// push t2 into high side of t1, may increase height by 1 so rebalance
rebalance t11 k1 (balance comparer t12 k t2)
@@ -491,13 +485,11 @@ namespace Microsoft.FSharp.Collections
iter (fun x -> arr.[!j] <- x; j := !j + 1) s
let toArray s =
- let n = (count s)
+ let n = size s
let res = Array.zeroCreate n
copyToArray s res 0;
res
-
-
let rec mkFromEnumerator comparer acc (e: IEnumerator<_>) =
if e.MoveNext() then
mkFromEnumerator comparer (add comparer e.Current acc) e
@@ -582,7 +574,7 @@ namespace Microsoft.FSharp.Collections
#endif
Set<'T>(s.Comparer,SetTree.remove s.Comparer value s.Tree)
- member s.Count = SetTree.count s.Tree
+ member s.Count = SetTree.size s.Tree
member s.Contains(value) =
#if TRACE_SETS_AND_MAPS
From cbc0d284276d7c1ca9ac46f65e6ff8c867e9e438 Mon Sep 17 00:00:00 2001
From: Paul Westcott
Date: Tue, 24 Jul 2018 16:21:19 +1000
Subject: [PATCH 3/3] Tagged collections Map + Set count from O(n) to O(1) and
rebalance via size
---
src/utils/TaggedCollections.fs | 180 +++++++++++++++------------------
1 file changed, 81 insertions(+), 99 deletions(-)
diff --git a/src/utils/TaggedCollections.fs b/src/utils/TaggedCollections.fs
index 232d3b7505..9e31c907eb 100644
--- a/src/utils/TaggedCollections.fs
+++ b/src/utils/TaggedCollections.fs
@@ -18,10 +18,10 @@ namespace Internal.Utilities.Collections.Tagged
[]
[]
type SetTree<'T> =
- | SetEmpty // height = 0
- | SetNode of 'T * SetTree<'T> * SetTree<'T> * int // height = int
+ | SetEmpty // size = 0
+ | SetNode of 'T * SetTree<'T> * SetTree<'T> * size:int
#if ONE
- | SetOne of 'T // height = 1
+ | SetOne of 'T // size = 1
#endif
// OPTIMIZATION: store SetNode(k,SetEmpty,SetEmpty,1) ---> SetOne(k)
@@ -33,13 +33,13 @@ namespace Internal.Utilities.Collections.Tagged
module SetTree =
let empty = SetEmpty
- let height t =
+ let inline size t =
match t with
| SetEmpty -> 0
#if ONE
| SetOne _ -> 1
#endif
- | SetNode (_,_,_,h) -> h
+ | SetNode (size=s) -> s
#if CHECKED
let rec checkInvariant t =
@@ -55,54 +55,52 @@ namespace Internal.Utilities.Collections.Tagged
let inline SetOne(x) = SetNode(x,SetEmpty,SetEmpty,1)
#endif
- let tolerance = 2
-
- let mk l hl k r hr =
+ let mk l k r =
#if ONE
- if hl = 0 && hr = 0 then SetOne (k)
- else
+ match l,r with
+ | SetEmpty,SetEmpty -> SetOne (k)
+ | _ ->
#endif
- let m = if hl < hr then hr else hl
- SetNode(k,l,r,m+1)
+ SetNode(k,l,r,(size l)+(size r)+1)
let rebalance t1 k t2 =
- let t1h = height t1
- let t2h = height t2
- if t2h > t1h + tolerance then // right is heavier than left
+ let t1s = size t1
+ let t2s = size t2
+ if (t2s >>> 1) > t1s then (* right is over twice as heavy as left *)
match t2 with
| SetNode(t2k,t2l,t2r,_) ->
- // one of the nodes must have height > height t1 + 1
- let t2lh = height t2l
- if t2lh > t1h + 1 then // balance left: combination
- match t2l with
- | SetNode(t2lk,t2ll,t2lr,_) ->
- let l = mk t1 t1h k t2ll (height t2ll)
- let r = mk t2lr (height t2lr) t2k t2r (height t2r)
- mk l (height l) t2lk r (height r)
- | _ -> failwith "rebalance"
- else // rotate left
- let l = mk t1 t1h k t2l t2lh
- mk l (height l) t2k t2r (height t2r)
+ (* one of the nodes must have size > size t1 *)
+ if size t2l > t1s then (* balance left: combination *)
+ match t2l with
+ | SetNode(t2lk,t2ll,t2lr,_) ->
+ mk (mk t1 k t2ll) t2lk (mk t2lr t2k t2r)
+#if ONE
+ | SetOne(t2lk) ->
+ mk (mk t1 k empty) t2lk (mk empty t2k t2r)
+#endif
+ | SetEmpty -> failwith "rebalance"
+ else (* rotate left *)
+ mk (mk t1 k t2l) t2k t2r
| _ -> failwith "rebalance"
else
- if t1h > t2h + tolerance then // left is heavier than right
- match t1 with
- | SetNode(t1k,t1l,t1r,_) ->
- // one of the nodes must have height > height t2 + 1
- let t1rh = height t1r
- if t1rh > t2h + 1 then
- // balance right: combination
- match t1r with
- | SetNode(t1rk,t1rl,t1rr,_) ->
- let l = mk t1l (height t1l) t1k t1rl (height t1rl)
- let r = mk t1rr (height t1rr) k t2 t2h
- mk l (height l) t1rk r (height r)
- | _ -> failwith "rebalance"
- else
- let r = mk t1r t1rh k t2 t2h
- mk t1l (height t1l) t1k r (height r)
- | _ -> failwith "rebalance"
- else mk t1 t1h k t2 t2h
+ if (t1s >>> 1) > t2s then (* left is over twice as heavy as right *)
+ match t1 with
+ | SetNode(t1k,t1l,t1r,_) ->
+ (* one of the nodes must have size > size t2 *)
+ if size t1r > t2s then
+ (* balance right: combination *)
+ match t1r with
+ | SetNode(t1rk,t1rl,t1rr,_) ->
+ mk (mk t1l t1k t1rl) t1rk (mk t1rr k t2)
+#if ONE
+ | SetOne(t1rk) ->
+ mk (mk t1l t1k empty) t1rk (mk empty k t2)
+#endif
+ | SetEmpty -> failwith "rebalance"
+ else
+ mk t1l t1k (mk t1r k t2)
+ | _ -> failwith "rebalance"
+ else mk t1 k t2
let rec add (comparer: IComparer<'T>) k t =
match t with
@@ -124,7 +122,7 @@ namespace Internal.Utilities.Collections.Tagged
let rec balance comparer t1 k t2 =
// Given t1 < k < t2 where t1 and t2 are "balanced",
// return a balanced tree for .
- // Recall: balance means subtrees heights differ by at most "tolerance"
+ // Recall: balance means subtrees size of trees differ by a factor of 2
match t1,t2 with
| SetEmpty,t2 -> add comparer k t2 // drop t1 = empty
| t1,SetEmpty -> add comparer k t1 // drop t2 = empty
@@ -132,22 +130,22 @@ namespace Internal.Utilities.Collections.Tagged
| SetOne k1,t2 -> add comparer k (add comparer k1 t2)
| t1,SetOne k2 -> add comparer k (add comparer k2 t1)
#endif
- | SetNode(k1,t11,t12,t1h),SetNode(k2,t21,t22,t2h) ->
+ | SetNode(k1,t11,t12,s1),SetNode(k2,t21,t22,s2) ->
// Have: (t11 < k1 < t12) < k < (t21 < k2 < t22)
- // Either (a) h1,h2 differ by at most 2 - no rebalance needed.
- // (b) h1 too small, i.e. h1+2 < h2
- // (c) h2 too small, i.e. h2+2 < h1
- if t1h+tolerance < t2h then
+ // Either (a) h1,h2 differ by at most a factory of 2 - no rebalance needed.
+ // (b) h1 too small
+ // (c) h2 too small
+ if (s2 >>> 1) > s1 then
// case: b, h1 too small
// push t1 into low side of t2, may increase height by 1 so rebalance
rebalance (balance comparer t1 k t21) k2 t22
- elif t2h+tolerance < t1h then
+ elif (s1 >>> 1) > s2 then
// case: c, h2 too small
// push t2 into high side of t1, may increase height by 1 so rebalance
rebalance t11 k1 (balance comparer t12 k t2)
else
// case: a, h1 and h2 meet balance requirement
- mk t1 t1h k t2 t2h
+ mk t1 k t2
let rec split (comparer : IComparer<'T>) pivot t =
// Given a pivot and a set t
@@ -182,7 +180,7 @@ namespace Internal.Utilities.Collections.Tagged
| SetNode (k2,l,r,_) ->
match l with
| SetEmpty -> k2,r
- | _ -> let k3,l' = spliceOutSuccessor l in k3,mk l' (height l') k2 r (height r)
+ | _ -> let k3,l' = spliceOutSuccessor l in k3,mk l' k2 r
let rec remove (comparer: IComparer<'T>) k t =
match t with
@@ -202,7 +200,7 @@ namespace Internal.Utilities.Collections.Tagged
| _,SetEmpty -> l
| _ ->
let sk,r' = spliceOutSuccessor r
- mk l (height l) sk r' (height r')
+ mk l sk r'
else rebalance l k2 (remove comparer k r)
let rec contains (comparer: IComparer<'T>) k t =
@@ -288,16 +286,6 @@ namespace Internal.Utilities.Collections.Tagged
let diff comparer a b = diffAux comparer b a
- let rec countAux s acc =
- match s with
- | SetNode(_,l,r,_) -> countAux l (countAux r (acc+1))
-#if ONE
- | SetOne(k) -> acc+1
-#endif
- | SetEmpty -> acc
-
- let count s = countAux s 0
-
let rec union comparer t1 t2 =
// Perf: tried bruteForce for low heights, but nothing significant
match t1,t2 with
@@ -553,7 +541,7 @@ namespace Internal.Utilities.Collections.Tagged
iter (fun x -> arr.[!j] <- x; j := !j + 1) s
let toArray s =
- let n = (count s)
+ let n = (size s)
let res = Array.zeroCreate n
copyToArray s res 0;
res
@@ -585,7 +573,7 @@ namespace Internal.Utilities.Collections.Tagged
member s.Add(x) : Set<'T,'ComparerTag> = refresh s (SetTree.add comparer x tree)
member s.Remove(x) : Set<'T,'ComparerTag> = refresh s (SetTree.remove comparer x tree)
- member s.Count = SetTree.count tree
+ member s.Count = SetTree.size tree
member s.Contains(x) = SetTree.contains comparer x tree
member s.Iterate(x) = SetTree.iter x tree
member s.Fold f x = SetTree.fold f tree x
@@ -686,7 +674,7 @@ namespace Internal.Utilities.Collections.Tagged
member s.Contains(x) = SetTree.contains comparer x tree
member s.CopyTo(arr,i) = SetTree.copyToArray tree arr i
member s.IsReadOnly = true
- member s.Count = SetTree.count tree
+ member s.Count = SetTree.size tree
interface IEnumerable<'T> with
member s.GetEnumerator() = SetTree.toSeq tree
@@ -708,21 +696,20 @@ namespace Internal.Utilities.Collections.Tagged
#if ONE
| MapOne of 'Key * 'T
#endif
- | MapNode of 'Key * 'T * MapTree<'Key,'T> * MapTree<'Key,'T> * int
-
+ | MapNode of 'Key * 'T * MapTree<'Key,'T> * MapTree<'Key,'T> * size:int
[]
module MapTree =
let empty = MapEmpty
- let inline height x =
+ let inline size x =
match x with
| MapEmpty -> 0
#if ONE
| MapOne _ -> 1
#endif
- | MapNode(_,_,_,_,h) -> h
+ | MapNode(size=s) -> s
let inline isEmpty m =
match m with
@@ -735,57 +722,52 @@ namespace Internal.Utilities.Collections.Tagged
| MapEmpty,MapEmpty -> MapOne(k,v)
| _ ->
#endif
- let hl = height l
- let hr = height r
- let m = if hl < hr then hr else hl
- MapNode(k,v,l,r,m+1)
+ MapNode(k,v,l,r,(size l)+(size r)+1)
let rebalance t1 k v t2 =
- let t1h = height t1
- let t2h = height t2
- if t2h > t1h + 2 then // right is heavier than left
+ let t1s = size t1
+ let t2s = size t2
+ if (t2s >>> 1) > t1s then (* right is over twice as heavy as left *)
match t2 with
| MapNode(t2k,t2v,t2l,t2r,_) ->
- // one of the nodes must have height > height t1 + 1
- if height t2l > t1h + 1 then // balance left: combination
+ (* one of the nodes must have size > size t1 *)
+ if size t2l > t1s then (* balance left: combination *)
match t2l with
| MapNode(t2lk,t2lv,t2ll,t2lr,_) ->
mk (mk t1 k v t2ll) t2lk t2lv (mk t2lr t2k t2v t2r)
- | _ -> failwith "rebalance"
- else // rotate left
+#if ONE
+ | MapOne(t2lk,t2lv) ->
+ mk (mk t1 k v empty) t2lk t2lv (mk empty t2k t2v t2r)
+#endif
+ | MapEmpty -> failwith "rebalance"
+ else (* rotate left *)
mk (mk t1 k v t2l) t2k t2v t2r
| _ -> failwith "rebalance"
else
- if t1h > t2h + 2 then // left is heavier than right
+ if (t1s >>> 1) > t2s then (* left is over twice as heavy as right *)
match t1 with
| MapNode(t1k,t1v,t1l,t1r,_) ->
- // one of the nodes must have height > height t2 + 1
- if height t1r > t2h + 1 then
- // balance right: combination
+ (* one of the nodes must have size > size t2 *)
+ if size t1r > t2s then
+ (* balance right: combination *)
match t1r with
| MapNode(t1rk,t1rv,t1rl,t1rr,_) ->
mk (mk t1l t1k t1v t1rl) t1rk t1rv (mk t1rr k v t2)
- | _ -> failwith "rebalance"
+#if ONE
+ | MapOne(t1rk,t1rv) ->
+ mk (mk t1l t1k t1v empty) t1rk t1rv (mk empty k v t2)
+#endif
+ | MapEmpty -> failwith "rebalance"
else
mk t1l t1k t1v (mk t1r k v t2)
| _ -> failwith "rebalance"
else mk t1 k v t2
- let rec sizeAux acc m =
- match m with
- | MapEmpty -> acc
-#if ONE
- | MapOne _ -> acc + 1
-#endif
- | MapNode(_,_,l,r,_) -> sizeAux (sizeAux (acc+1) l) r
-
#if ONE
#else
let MapOne(k,v) = MapNode(k,v,MapEmpty,MapEmpty,1)
#endif
- let count x = sizeAux 0 x
-
let rec add (comparer: IComparer<'T>) k v m =
match m with
| MapEmpty -> MapOne(k,v)
@@ -1122,7 +1104,7 @@ namespace Internal.Utilities.Collections.Tagged
member m.Partition(f) =
let r1,r2 = MapTree.partition comparer f tree
refresh m r1, refresh m r2
- member m.Count = MapTree.count tree
+ member m.Count = MapTree.size tree
member m.ContainsKey(k) = MapTree.containsKey comparer k tree
member m.Remove(k) = refresh m (MapTree.remove comparer k tree)
member m.TryFind(k) = MapTree.tryFind comparer k tree