未验证 提交 4990f64f 编写于 作者: D Don Syme 提交者: GitHub

Apply formatting to "Utilities" (#13171)

* change formatting settings

* apply formatting
上级 e8fc5fb1
......@@ -13,7 +13,6 @@ vsintegration/
# Explicitly unformatted implementation files
src/FSharp.Core/**/*.fs
src/Compiler/**/*.fs
src/Compiler/AbstractIL/**/*.fs
src/Compiler/Checking/**/*.fs
src/Compiler/CodeGen/**/*.fs
......@@ -27,9 +26,12 @@ src/Compiler/Service/**/*.fs
src/Compiler/Symbols/**/*.fs
src/Compiler/SyntaxTree/**/*.fs
src/Compiler/TypedTree/**/*.fs
src/Compiler/Utilities/**/*.fs
src/Microsoft.FSharp.Compiler/**/*.fs
# Fantomas limitations on implementation files (to investigate)
src/Compiler/Utilities/lib.fs
# Fantomas limitations on signature files (to investigate)
src/Compiler/AbstractIL/ilread.fsi
......
......@@ -8,24 +8,28 @@ open System
/// Given an offset and a radius from that offset, does mChar exist in that part of str?
let inline existsInWin (mChar: char) (str: string) (offset: int) (rad: int) =
let startAt = Math.Max(0, offset - rad)
let endAt = Math.Min(offset + rad, str.Length - 1)
if endAt - startAt < 0 then false
let endAt = Math.Min(offset + rad, str.Length - 1)
if endAt - startAt < 0 then
false
else
let rec exists index =
if str[index] = mChar then true
elif index = endAt then false
else exists (index + 1)
exists startAt
let jaro (s1: string) (s2: string) =
let jaro (s1: string) (s2: string) =
// The radius is half of the lesser of the two string lengths rounded up.
let matchRadius =
let matchRadius =
let minLen = Math.Min(s1.Length, s2.Length)
minLen / 2 + minLen % 2
let rec nextChar (s1:string) (s2:string) i c =
let rec nextChar (s1: string) (s2: string) i c =
if i < s1.Length then
let c = s1[i]
if not (existsInWin c s2 i matchRadius) then
nextChar s1 s2 (i + 1) c
else
......@@ -33,52 +37,67 @@ let jaro (s1: string) (s2: string) =
else
struct (i, c)
// The sets of common characters and their lengths as floats
// The sets of common characters and their lengths as floats
// The number of transpositions within the sets of common characters.
let struct (transpositions, c1length, c2length) =
let rec loop i j mismatches c1length c2length =
if i < s1.Length && j < s2.Length then
let struct (ti, ci) = nextChar s1 s2 i ' '
let struct (tj, cj) = nextChar s2 s1 j ' '
if ci <> cj then
loop (ti + 1) (tj + 1) (mismatches + 1) (c1length + 1) (c2length + 1)
else
loop (ti + 1) (tj + 1) mismatches (c1length + 1) (c2length + 1)
else struct (i, j, mismatches, c1length, c2length)
else
struct (i, j, mismatches, c1length, c2length)
let struct (i, j, mismatches, c1length, c2length) = loop 0 0 0 0 0
let rec loop (s1:string) (s2:string) i length =
let rec loop (s1: string) (s2: string) i length =
if i < s1.Length - 1 then
let c = s1[i]
if existsInWin c s2 i matchRadius then
if existsInWin c s2 i matchRadius then
loop s1 s2 (i + 1) (length + 1)
else
loop s1 s2 (i + 1) length
else
length
let c1length = loop s1 s2 i c1length |> float
let c2length = loop s2 s1 j c2length |> float
struct ((float mismatches + abs (c1length - c2length)) / 2.0, c1length, c2length)
let tLength = Math.Max(c1length, c2length)
// The jaro distance as given by 1/3 ( m2/|s1| + m1/|s2| + (mc-t)/mc )
let result = (c1length / float s1.Length + c2length / float s2.Length + (tLength - transpositions) / tLength) / 3.0
// This is for cases where |s1|, |s2| or m are zero
if Double.IsNaN result then 0.0 else result
let result =
(c1length / float s1.Length
+ c2length / float s2.Length
+ (tLength - transpositions) / tLength)
/ 3.0
// This is for cases where |s1|, |s2| or m are zero
if Double.IsNaN result then
0.0
else
result
/// Calculates the Jaro-Winkler edit distance between two strings.
/// The edit distance is a metric that allows to measure the amount of similarity between two strings.
let JaroWinklerDistance s1 s2 =
let JaroWinklerDistance s1 s2 =
let jaroScore = jaro s1 s2
// Accumulate the number of matching initial characters
let maxLength = (min s1.Length s2.Length) - 1
let rec calcL i acc =
if i > maxLength || s1[i] <> s2[i] then acc
else calcL (i + 1) (acc + 1.0)
if i > maxLength || s1[i] <> s2[i] then
acc
else
calcL (i + 1) (acc + 1.0)
let l = min (calcL 0 0.0) 4.0
// Calculate the JW distance
let p = 0.1
......@@ -88,7 +107,7 @@ let JaroWinklerDistance s1 s2 =
/// also known as the "optimal string alignment" distance.
/// - read more at https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance
/// - Implementation taken from http://www.navision-blog.de/2008/11/01/damerau-levenshtein-distance-in-fsharp-part-ii/
let private calcDamerauLevenshtein (a:string, b:string) =
let private calcDamerauLevenshtein (a: string, b: string) =
let m = b.Length + 1
let mutable lastLine = Array.init m id
let mutable lastLastLine = Array.zeroCreate m
......@@ -96,34 +115,32 @@ let private calcDamerauLevenshtein (a:string, b:string) =
for i in 1 .. a.Length do
actLine[0] <- i
for j in 1 .. b.Length do
let cost = if a[i-1] = b[j-1] then 0 else 1
let cost = if a[i - 1] = b[j - 1] then 0 else 1
let deletion = lastLine[j] + 1
let insertion = actLine[j-1] + 1
let substitution = lastLine[j-1] + cost
actLine[j] <-
deletion
|> min insertion
|> min substitution
let insertion = actLine[j - 1] + 1
let substitution = lastLine[j - 1] + cost
actLine[j] <- deletion |> min insertion |> min substitution
if i > 1 && j > 1 then
if a[i-1] = b[j-2] && a[i-2] = b[j-1] then
let transposition = lastLastLine[j-2] + cost
actLine[j] <- min actLine[j] transposition
if a[i - 1] = b[j - 2] && a[i - 2] = b[j - 1] then
let transposition = lastLastLine[j - 2] + cost
actLine[j] <- min actLine[j] transposition
// swap lines
let temp = lastLastLine
lastLastLine <- lastLine
lastLine <- actLine
actLine <- temp
lastLine[b.Length]
/// Calculates the edit distance between two strings.
/// The edit distance is a metric that allows to measure the amount of difference between two strings
/// The edit distance is a metric that allows to measure the amount of difference between two strings
/// and shows how many edit operations (insert, delete, substitution) are needed to transform one string into the other.
let CalculateEditDistance(a:string, b:string) =
let CalculateEditDistance (a: string, b: string) =
if a.Length > b.Length then
calcDamerauLevenshtein(a, b)
calcDamerauLevenshtein (a, b)
else
calcDamerauLevenshtein(b, a)
\ No newline at end of file
calcDamerauLevenshtein (b, a)
......@@ -3,81 +3,86 @@
namespace Internal.Utilities.Collections
open System.Collections.Generic
// Each entry in the HashMultiMap dictionary has at least one entry. Under normal usage each entry has _only_
// one entry. So use two hash tables: one for the main entries and one for the overflow.
[<Sealed>]
type internal HashMultiMap<'Key,'Value>(size: int, comparer: IEqualityComparer<'Key>) =
type internal HashMultiMap<'Key, 'Value>(size: int, comparer: IEqualityComparer<'Key>) =
let firstEntries = Dictionary<_, _>(size, comparer)
let firstEntries = Dictionary<_,_>(size,comparer)
let rest = Dictionary<_, _>(3, comparer)
let rest = Dictionary<_,_>(3,comparer)
new (comparer : IEqualityComparer<'Key>) = HashMultiMap<'Key,'Value>(11, comparer)
new(comparer: IEqualityComparer<'Key>) = HashMultiMap<'Key, 'Value>(11, comparer)
new (entries : seq<'Key * 'Value>, comparer : IEqualityComparer<'Key>) as x =
new HashMultiMap<'Key,'Value>(11, comparer)
then entries |> Seq.iter (fun (k,v) -> x.Add(k,v))
new(entries: seq<'Key * 'Value>, comparer: IEqualityComparer<'Key>) as x =
new HashMultiMap<'Key, 'Value>(11, comparer)
then entries |> Seq.iter (fun (k, v) -> x.Add(k, v))
member x.GetRest(k) =
match rest.TryGetValue k with
| true, res -> res
| _ -> []
member x.Add(y,z) =
member x.Add(y, z) =
match firstEntries.TryGetValue y with
| true, res ->
rest[y] <- res :: x.GetRest(y)
| true, res -> rest[y] <- res :: x.GetRest(y)
| _ -> ()
firstEntries[y] <- z
member x.Clear() =
firstEntries.Clear()
rest.Clear()
member x.Clear() =
firstEntries.Clear()
rest.Clear()
member x.FirstEntries = firstEntries
member x.Rest = rest
member x.Copy() =
let res = HashMultiMap<'Key,'Value>(firstEntries.Count,firstEntries.Comparer)
for kvp in firstEntries do
res.FirstEntries.Add(kvp.Key,kvp.Value)
member x.Copy() =
let res = HashMultiMap<'Key, 'Value>(firstEntries.Count, firstEntries.Comparer)
for kvp in firstEntries do
res.FirstEntries.Add(kvp.Key, kvp.Value)
for kvp in rest do
res.Rest.Add(kvp.Key, kvp.Value)
for kvp in rest do
res.Rest.Add(kvp.Key,kvp.Value)
res
member x.Item
with get(y : 'Key) =
member x.Item
with get (y: 'Key) =
match firstEntries.TryGetValue y with
| true, res -> res
| _ -> raise (KeyNotFoundException("The item was not found in collection"))
and set (y:'Key) (z:'Value) =
x.Replace(y,z)
and set (y: 'Key) (z: 'Value) = x.Replace(y, z)
member x.FindAll(y) =
member x.FindAll(y) =
match firstEntries.TryGetValue y with
| true, res -> res :: x.GetRest(y)
| _ -> []
member x.Fold f acc =
member x.Fold f acc =
let mutable res = acc
for kvp in firstEntries do
res <- f kvp.Key kvp.Value res
match x.GetRest(kvp.Key) with
| [] -> ()
| rest ->
| rest ->
for z in rest do
res <- f kvp.Key z res
res
member x.Iterate(f) =
member x.Iterate(f) =
for kvp in firstEntries do
f kvp.Key kvp.Value
match x.GetRest(kvp.Key) with
| [] -> ()
| rest ->
| rest ->
for z in rest do
f kvp.Key z
......@@ -85,28 +90,25 @@ type internal HashMultiMap<'Key,'Value>(size: int, comparer: IEqualityComparer<'
member x.ContainsKey(y) = firstEntries.ContainsKey(y)
member x.Remove(y) =
member x.Remove(y) =
match firstEntries.TryGetValue y with
// NOTE: If not ok then nothing to remove - nop
| true, _res ->
// We drop the FirstEntry. Here we compute the new FirstEntry and residue MoreEntries
match rest.TryGetValue y with
| true, res ->
match res with
| [h] ->
firstEntries[y] <- h;
match res with
| [ h ] ->
firstEntries[y] <- h
rest.Remove(y) |> ignore
| h :: t ->
| h :: t ->
firstEntries[y] <- h
rest[y] <- t
| _ ->
()
| _ ->
firstEntries.Remove(y) |> ignore
| _ -> ()
| _ -> firstEntries.Remove(y) |> ignore
| _ -> ()
member x.Replace(y,z) =
firstEntries[y] <- z
member x.Replace(y, z) = firstEntries[y] <- z
member x.TryFind(y) =
match firstEntries.TryGetValue y with
......@@ -117,49 +119,60 @@ type internal HashMultiMap<'Key,'Value>(size: int, comparer: IEqualityComparer<'
interface IEnumerable<KeyValuePair<'Key, 'Value>> with
member s.GetEnumerator() =
member s.GetEnumerator() =
let elems = List<_>(firstEntries.Count + rest.Count)
for kvp in firstEntries do
elems.Add(kvp)
for z in s.GetRest(kvp.Key) do
elems.Add(KeyValuePair(kvp.Key, z))
elems.Add(KeyValuePair(kvp.Key, z))
(elems.GetEnumerator() :> IEnumerator<_>)
interface System.Collections.IEnumerable with
member s.GetEnumerator() = ((s :> seq<_>).GetEnumerator() :> System.Collections.IEnumerator)
member s.GetEnumerator() =
((s :> seq<_>).GetEnumerator() :> System.Collections.IEnumerator)
interface IDictionary<'Key, 'Value> with
interface IDictionary<'Key, 'Value> with
member s.Item
with get x = s[x]
and set x v = s[x] <- v
member s.Item
with get x = s[x]
and set x v = s[x] <- v
member s.Keys = ([| for kvp in s -> kvp.Key |] :> ICollection<'Key>)
member s.Values = ([| for kvp in s -> kvp.Value |] :> ICollection<'Value>)
member s.Add(k,v) = s[k] <- v
member s.Add(k, v) = s[k] <- v
member s.ContainsKey(k) = s.ContainsKey(k)
member s.TryGetValue(k,r) = match s.TryFind k with Some v-> (r <- v; true) | _ -> false
member s.TryGetValue(k, r) =
match s.TryFind k with
| Some v ->
(r <- v
true)
| _ -> false
member s.Remove(k:'Key) =
let res = s.ContainsKey(k) in
s.Remove(k); res
member s.Remove(k: 'Key) =
let res = s.ContainsKey(k) in
s.Remove(k)
res
interface ICollection<KeyValuePair<'Key, 'Value>> with
interface ICollection<KeyValuePair<'Key, 'Value>> with
member s.Add(x) = s[x.Key] <- x.Value
member s.Clear() = s.Clear()
member s.Clear() = s.Clear()
member s.Remove(x) =
member s.Remove(x) =
match s.TryFind x.Key with
| Some v ->
| Some v ->
if Unchecked.equals v x.Value then
s.Remove(x.Key)
true
| _ -> false
......@@ -168,9 +181,9 @@ type internal HashMultiMap<'Key,'Value>(size: int, comparer: IEqualityComparer<'
| Some v when Unchecked.equals v x.Value -> true
| _ -> false
member s.CopyTo(arr,arrIndex) = s |> Seq.iteri (fun j x -> arr[arrIndex+j] <- x)
member s.CopyTo(arr, arrIndex) =
s |> Seq.iteri (fun j x -> arr[arrIndex + j] <- x)
member s.IsReadOnly = false
member s.Count = s.Count
......@@ -5,8 +5,7 @@ open System.Collections.Immutable
[<RequireQualifiedAccess>]
module ImmutableArrayBuilder =
let create size : ImmutableArray<'T>.Builder =
ImmutableArray.CreateBuilder(size)
let create size : ImmutableArray<'T>.Builder = ImmutableArray.CreateBuilder(size)
[<RequireQualifiedAccess>]
module ImmutableArray =
......@@ -23,8 +22,10 @@ module ImmutableArray =
invalidArg "n" "Below zero."
let builder = ImmutableArray.CreateBuilder(n)
for i = 0 to n - 1 do
builder.Add(f i)
builder.MoveToImmutable()
let iter f (arr: ImmutableArray<'T>) =
......@@ -55,8 +56,10 @@ module ImmutableArray =
| 1 -> ImmutableArray.Create(mapper arr[0])
| _ ->
let builder = ImmutableArray.CreateBuilder(arr.Length)
for i = 0 to arr.Length - 1 do
builder.Add(mapper arr[i])
builder.MoveToImmutable()
let mapi (mapper: int -> 'T -> 'U) (arr: ImmutableArray<'T>) : ImmutableArray<_> =
......@@ -65,120 +68,155 @@ module ImmutableArray =
| 1 -> ImmutableArray.Create(mapper 0 arr[0])
| _ ->
let builder = ImmutableArray.CreateBuilder(arr.Length)
for i = 0 to arr.Length - 1 do
builder.Add(mapper i arr[i])
builder.MoveToImmutable()
let map2 (mapper: 'T1 -> 'T2 -> 'T) (arr1: ImmutableArray<'T1>) (arr2: ImmutableArray<'T2>) : ImmutableArray<_> =
if arr1.Length <> arr2.Length then
invalidOp "Block lengths do not match."
match arr1.Length with
| 0 -> ImmutableArray.Empty
| 1 -> ImmutableArray.Create(mapper arr1[0] arr2[0])
| n ->
let builder = ImmutableArray.CreateBuilder(n)
for i = 0 to n - 1 do
builder.Add(mapper arr1[i] arr2[i])
builder.MoveToImmutable()
let mapi2 (mapper: int -> 'T1 -> 'T2 -> 'T) (arr1: ImmutableArray<'T1>) (arr2: ImmutableArray<'T2>) : ImmutableArray<_> =
if arr1.Length <> arr2.Length then
invalidOp "Block lengths do not match."
match arr1.Length with
| 0 -> ImmutableArray.Empty
| 1 -> ImmutableArray.Create(mapper 0 arr1[0] arr2[0])
| n ->
let builder = ImmutableArray.CreateBuilder(n)
for i = 0 to n - 1 do
builder.Add(mapper i arr1[i] arr2[i])
builder.MoveToImmutable()
let concat (arrs: ImmutableArray<ImmutableArray<'T>>) : ImmutableArray<'T> =
match arrs.Length with
| 0 -> ImmutableArray.Empty
| 1 -> arrs[0]
| 2 -> arrs[0].AddRange(arrs[1])
| 2 -> arrs[ 0 ].AddRange(arrs[1])
| _ ->
let mutable acc = 0
let mutable acc = 0
for h in arrs do
acc <- acc + h.Length
let builder = ImmutableArray.CreateBuilder(acc)
for i = 0 to arrs.Length - 1 do
builder.AddRange(arrs[i])
builder.MoveToImmutable()
let forall predicate (arr: ImmutableArray<'T>) =
let len = arr.Length
let rec loop i = i >= len || (predicate arr[i] && loop (i+1))
let rec loop i =
i >= len || (predicate arr[i] && loop (i + 1))
loop 0
let forall2 predicate (arr1: ImmutableArray<'T1>) (arr2: ImmutableArray<'T2>) =
if arr1.Length <> arr2.Length then
invalidOp "Block lengths do not match."
let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(predicate)
let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt (predicate)
let len1 = arr1.Length
let rec loop i = i >= len1 || (f.Invoke(arr1[i], arr2[i]) && loop (i+1))
let rec loop i =
i >= len1 || (f.Invoke(arr1[i], arr2[i]) && loop (i + 1))
loop 0
let tryFind predicate (arr: ImmutableArray<'T>) =
let rec loop i =
if i >= arr.Length then None else
if predicate arr[i] then Some arr[i] else loop (i+1)
loop 0
let rec loop i =
if i >= arr.Length then
None
else if predicate arr[i] then
Some arr[i]
else
loop (i + 1)
loop 0
let tryFindIndex predicate (arr: ImmutableArray<'T>) =
let len = arr.Length
let rec go n = if n >= len then None elif predicate arr[n] then Some n else go (n+1)
go 0
let len = arr.Length
let rec go n =
if n >= len then None
elif predicate arr[n] then Some n
else go (n + 1)
go 0
let tryPick chooser (arr: ImmutableArray<'T>) =
let rec loop i =
if i >= arr.Length then None else
match chooser arr[i] with
| None -> loop(i+1)
| res -> res
loop 0
let rec loop i =
if i >= arr.Length then
None
else
match chooser arr[i] with
| None -> loop (i + 1)
| res -> res
loop 0
let ofSeq (xs: 'T seq) =
ImmutableArray.CreateRange(xs)
let ofSeq (xs: 'T seq) = ImmutableArray.CreateRange(xs)
let append (arr1: ImmutableArray<'T1>) (arr2: ImmutableArray<'T1>) : ImmutableArray<_> =
arr1.AddRange(arr2)
let append (arr1: ImmutableArray<'T1>) (arr2: ImmutableArray<'T1>) : ImmutableArray<_> = arr1.AddRange(arr2)
let createOne (item: 'T) : ImmutableArray<_> =
ImmutableArray.Create(item)
let createOne (item: 'T) : ImmutableArray<_> = ImmutableArray.Create(item)
let filter predicate (arr: ImmutableArray<'T>) : ImmutableArray<'T> =
let builder = ImmutableArray.CreateBuilder(arr.Length)
for i = 0 to arr.Length - 1 do
if predicate arr[i] then
builder.Add(arr[i])
builder.Capacity <- builder.Count
builder.MoveToImmutable()
let exists predicate (arr: ImmutableArray<'T>) =
let len = arr.Length
let rec loop i = i < len && (predicate arr[i] || loop (i+1))
let rec loop i =
i < len && (predicate arr[i] || loop (i + 1))
len > 0 && loop 0
let choose (chooser: 'T -> 'U option) (arr: ImmutableArray<'T>) : ImmutableArray<'U> =
let builder = ImmutableArray.CreateBuilder(arr.Length)
for i = 0 to arr.Length - 1 do
let result = chooser arr[i]
if result.IsSome then
builder.Add(result.Value)
builder.Capacity <- builder.Count
builder.MoveToImmutable()
let isEmpty (arr: ImmutableArray<_>) = arr.IsEmpty
let fold folder state (arr: ImmutableArray<_>) =
let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt(folder)
let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt (folder)
let mutable state = state
for i = 0 to arr.Length - 1 do
for i = 0 to arr.Length - 1 do
state <- f.Invoke(state, arr[i])
state
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
namespace Internal.Utilities.Collections
open System
[<StructuralEquality; NoComparison>]
type internal ValueStrength<'T when 'T : not struct> =
| Strong of 'T
type internal ValueStrength<'T when 'T: not struct> =
| Strong of 'T
#if FX_NO_GENERIC_WEAKREFERENCE
| Weak of WeakReference
| Weak of WeakReference
#else
| Weak of WeakReference<'T>
| Weak of WeakReference<'T>
#endif
type internal AgedLookup<'Token, 'Key, 'Value when 'Value : not struct>(keepStrongly:int, areSimilar, ?requiredToKeep, ?keepMax: int) =
type internal AgedLookup<'Token, 'Key, 'Value when 'Value: not struct>(keepStrongly: int, areSimilar, ?requiredToKeep, ?keepMax: int) =
/// The list of items stored. Youngest is at the end of the list.
/// The choice of order is somewhat arbitrary. If the other way then adding
/// items would be O(1) and removing O(N).
let mutable refs:('Key*ValueStrength<'Value>) list = []
let mutable refs: ('Key * ValueStrength<'Value>) list = []
let mutable keepStrongly = keepStrongly
// The 75 here determines how long the list should be passed the end of strongly held
// references. Some operations are O(N) and we don't want to let things get out of
// hand.
let keepMax = defaultArg keepMax 75
let mutable keepMax = max keepStrongly keepMax
let requiredToKeep = defaultArg requiredToKeep (fun _ -> false)
let keepMax = defaultArg keepMax 75
let mutable keepMax = max keepStrongly keepMax
let requiredToKeep = defaultArg requiredToKeep (fun _ -> false)
/// Look up a the given key, return <c>None</c> if not found.
let TryPeekKeyValueImpl(data,key) =
let rec Lookup key = function
let TryPeekKeyValueImpl (data, key) =
let rec Lookup key =
function
// Treat a list of key-value pairs as a lookup collection.
// This function returns true if two keys are the same according to the predicate
// function passed in.
| []->None
| (similarKey,value) :: t->
if areSimilar(key,similarKey) then Some(similarKey,value)
else Lookup key t
Lookup key data
| [] -> None
| (similarKey, value) :: t ->
if areSimilar (key, similarKey) then
Some(similarKey, value)
else
Lookup key t
Lookup key data
/// Determines whether a particular key exists.
let Exists(data,key) = TryPeekKeyValueImpl(data,key).IsSome
let Exists (data, key) = TryPeekKeyValueImpl(data, key).IsSome
/// Set a particular key's value.
let Add(data,key,value) =
data @ [key,value]
let Add (data, key, value) = data @ [ key, value ]
/// Promote a particular key value.
let Promote (data, key, value) =
(data |> List.filter (fun (similarKey,_)-> not (areSimilar(key,similarKey)))) @ [ (key, value) ]
let Promote (data, key, value) =
(data |> List.filter (fun (similarKey, _) -> not (areSimilar (key, similarKey))))
@ [ (key, value) ]
/// Remove a particular key value.
let RemoveImpl (data, key) =
let keep = data |> List.filter (fun (similarKey,_)-> not (areSimilar(key,similarKey)))
let RemoveImpl (data, key) =
let keep =
data |> List.filter (fun (similarKey, _) -> not (areSimilar (key, similarKey)))
keep
let TryGetKeyValueImpl(data,key) =
match TryPeekKeyValueImpl(data,key) with
| Some(similarKey, value) as result ->
let TryGetKeyValueImpl (data, key) =
match TryPeekKeyValueImpl(data, key) with
| Some (similarKey, value) as result ->
// If the result existed, move it to the end of the list (more likely to keep it)
result,Promote (data,similarKey,value)
| None -> None,data
result, Promote(data, similarKey, value)
| None -> None, data
/// Remove weak entries from the list that have been collected.
let FilterAndHold(tok: 'Token) =
let FilterAndHold (tok: 'Token) =
ignore tok // reading 'refs' requires a token
[ for key,value in refs do
match value with
| Strong(value) -> yield (key,value)
| Weak(weakReference) ->
[
for key, value in refs do
match value with
| Strong (value) -> yield (key, value)
| Weak (weakReference) ->
#if FX_NO_GENERIC_WEAKREFERENCE
match weakReference.Target with
| null -> ()
| value -> yield key,(value:?>'Value) ]
match weakReference.Target with
| null -> ()
| value -> yield key, (value :?> 'Value)
]
#else
match weakReference.TryGetTarget () with
| false, _ -> ()
| true, value -> yield key, value ]
match weakReference.TryGetTarget() with
| false, _ -> ()
| true, value -> yield key, value
]
#endif
let AssignWithStrength(tok,newData) =
let AssignWithStrength (tok, newData) =
let actualLength = List.length newData
let tossThreshold = max 0 (actualLength - keepMax) // Delete everything less than this threshold
let weakThreshold = max 0 (actualLength - keepStrongly) // Weaken everything less than this threshold
let newData = newData|> List.mapi( fun n kv -> n,kv ) // Place the index.
let newData = newData |> List.filter (fun (n:int,v) -> n >= tossThreshold || requiredToKeep (snd v))
let newData =
newData
|> List.map( fun (n:int,(k,v)) ->
let handle =
if n<weakThreshold && not (requiredToKeep v) then
let newData = newData |> List.mapi (fun n kv -> n, kv) // Place the index.
let newData =
newData
|> List.filter (fun (n: int, v) -> n >= tossThreshold || requiredToKeep (snd v))
let newData =
newData
|> List.map (fun (n: int, (k, v)) ->
let handle =
if n < weakThreshold && not (requiredToKeep v) then
#if FX_NO_GENERIC_WEAKREFERENCE
Weak(WeakReference(v))
Weak(WeakReference(v))
#else
Weak(WeakReference<_>(v))
Weak(WeakReference<_>(v))
#endif
else
else
Strong(v)
k,handle )
k, handle)
ignore tok // Updating refs requires tok
refs <- newData
member al.TryPeekKeyValue(tok, key) =
member al.TryPeekKeyValue(tok, key) =
// Returns the original key value as well since it may be different depending on equality test.
let data = FilterAndHold(tok)
TryPeekKeyValueImpl(data,key)
member al.TryGetKeyValue(tok, key) =
TryPeekKeyValueImpl(data, key)
member al.TryGetKeyValue(tok, key) =
let data = FilterAndHold(tok)
let result,newData = TryGetKeyValueImpl(data,key)
AssignWithStrength(tok,newData)
let result, newData = TryGetKeyValueImpl(data, key)
AssignWithStrength(tok, newData)
result
member al.TryGet(tok, key) =
member al.TryGet(tok, key) =
let data = FilterAndHold(tok)
let result,newData = TryGetKeyValueImpl(data,key)
AssignWithStrength(tok,newData)
let result, newData = TryGetKeyValueImpl(data, key)
AssignWithStrength(tok, newData)
match result with
| Some(_,value) -> Some(value)
| Some (_, value) -> Some(value)
| None -> None
member al.Put(tok, key,value) =
member al.Put(tok, key, value) =
let data = FilterAndHold(tok)
let data = if Exists(data,key) then RemoveImpl (data,key) else data
let data = Add(data,key,value)
AssignWithStrength(tok,data) // This will remove extras
member al.Remove(tok, key) =
let data =
if Exists(data, key) then
RemoveImpl(data, key)
else
data
let data = Add(data, key, value)
AssignWithStrength(tok, data) // This will remove extras
member al.Remove(tok, key) =
let data = FilterAndHold(tok)
let newData = RemoveImpl (data,key)
AssignWithStrength(tok,newData)
let newData = RemoveImpl(data, key)
AssignWithStrength(tok, newData)
member al.Clear(tok) =
let _discards = FilterAndHold(tok)
AssignWithStrength(tok,[])
let _discards = FilterAndHold(tok)
AssignWithStrength(tok, [])
member al.Resize(tok, newKeepStrongly, ?newKeepMax) =
let newKeepMax = defaultArg newKeepMax 75
keepStrongly <- newKeepStrongly
keepMax <- max newKeepStrongly newKeepMax
let keep = FilterAndHold(tok)
AssignWithStrength(tok,keep)
let newKeepMax = defaultArg newKeepMax 75
keepStrongly <- newKeepStrongly
keepMax <- max newKeepStrongly newKeepMax
let keep = FilterAndHold(tok)
AssignWithStrength(tok, keep)
type internal MruCache<'Token, 'Key, 'Value when 'Value: not struct>
(
keepStrongly,
areSame,
?isStillValid: 'Key * 'Value -> bool,
?areSimilar,
?requiredToKeep,
?keepMax
) =
type internal MruCache<'Token, 'Key,'Value when 'Value : not struct>(keepStrongly, areSame, ?isStillValid : 'Key*'Value->bool, ?areSimilar, ?requiredToKeep, ?keepMax) =
/// Default behavior of <c>areSimilar</c> function is areSame.
let areSimilar = defaultArg areSimilar areSame
/// The list of items in the cache. Youngest is at the end of the list.
/// The choice of order is somewhat arbitrary. If the other way then adding
/// items would be O(1) and removing O(N).
let cache = AgedLookup<'Token, 'Key,'Value>(keepStrongly=keepStrongly,areSimilar=areSimilar,?keepMax=keepMax,?requiredToKeep=requiredToKeep)
let cache =
AgedLookup<'Token, 'Key, 'Value>(
keepStrongly = keepStrongly,
areSimilar = areSimilar,
?keepMax = keepMax,
?requiredToKeep = requiredToKeep
)
/// Whether or not this result value is still valid.
let isStillValid = defaultArg isStillValid (fun _ -> true)
member bc.ContainsSimilarKey(tok, key) =
member bc.ContainsSimilarKey(tok, key) =
match cache.TryPeekKeyValue(tok, key) with
| Some(_similarKey, _value)-> true
| Some (_similarKey, _value) -> true
| None -> false
member bc.TryGetAny(tok, key) =
member bc.TryGetAny(tok, key) =
match cache.TryPeekKeyValue(tok, key) with
| Some(similarKey, value)->
if areSame(similarKey,key) then Some(value)
else None
| Some (similarKey, value) ->
if areSame (similarKey, key) then
Some(value)
else
None
| None -> None
member bc.TryGet(tok, key) =
member bc.TryGet(tok, key) =
match cache.TryGetKeyValue(tok, key) with
| Some(similarKey, value) ->
if areSame(similarKey, key) && isStillValid(key,value) then Some value
else None
| Some (similarKey, value) ->
if areSame (similarKey, key) && isStillValid (key, value) then
Some value
else
None
| None -> None
member bc.TryGetSimilarAny(tok, key) =
member bc.TryGetSimilarAny(tok, key) =
match cache.TryGetKeyValue(tok, key) with
| Some(_, value) -> Some value
| Some (_, value) -> Some value
| None -> None
member bc.TryGetSimilar(tok, key) =
member bc.TryGetSimilar(tok, key) =
match cache.TryGetKeyValue(tok, key) with
| Some(_, value) ->
if isStillValid(key,value) then Some value
else None
| Some (_, value) ->
if isStillValid (key, value) then
Some value
else
None
| None -> None
member bc.Set(tok, key:'Key,value:'Value) =
cache.Put(tok, key,value)
member bc.RemoveAnySimilar(tok, key) =
cache.Remove(tok, key)
member bc.Clear(tok) =
cache.Clear(tok)
member bc.Set(tok, key: 'Key, value: 'Value) = cache.Put(tok, key, value)
member bc.RemoveAnySimilar(tok, key) = cache.Remove(tok, key)
member bc.Clear(tok) = cache.Clear(tok)
member bc.Resize(tok, newKeepStrongly, ?newKeepMax) =
cache.Resize(tok, newKeepStrongly, ?newKeepMax=newKeepMax)
cache.Resize(tok, newKeepStrongly, ?newKeepMax = newKeepMax)
......@@ -17,20 +17,22 @@ module internal PathMap =
let empty = PathMap Map.empty
let addMapping (src : string) (dst : string) (PathMap map) : PathMap =
let addMapping (src: string) (dst: string) (PathMap map) : PathMap =
// Normalise the path
let normalSrc = FileSystem.GetFullPathShim src
let oldPrefix =
if normalSrc.EndsWith dirSepStr then normalSrc
else normalSrc + dirSepStr
if normalSrc.EndsWith dirSepStr then
normalSrc
else
normalSrc + dirSepStr
// Always add a path separator
map |> Map.add oldPrefix dst |> PathMap
// Map a file path with its replacement.
// This logic replicates C#'s PathUtilities.NormalizePathPrefix
let apply (PathMap map) (filePath : string) : string =
let apply (PathMap map) (filePath: string) : string =
// Find the first key in the path map that matches a prefix of the
// normalized path. We expect the client to use consistent capitalization;
// we use ordinal (case-sensitive) comparisons.
......@@ -40,23 +42,26 @@ module internal PathMap =
// to check if it was a partial match
// e.g. for the map /goo=/bar and file name /goooo
if filePath.StartsWith(oldPrefix, StringComparison.Ordinal) then
let replacement = replacementPrefix + filePath.Substring (oldPrefix.Length - 1)
let replacement = replacementPrefix + filePath.Substring(oldPrefix.Length - 1)
// Normalize the path separators if used uniformly in the replacement
let hasSlash = replacementPrefix.IndexOf '/' >= 0
let hasBackslash = replacementPrefix.IndexOf '\\' >= 0
if hasSlash && not hasBackslash then replacement.Replace('\\', '/')
elif hasBackslash && not hasSlash then replacement.Replace('/', '\\')
else replacement
if hasSlash && not hasBackslash then
replacement.Replace('\\', '/')
elif hasBackslash && not hasSlash then
replacement.Replace('/', '\\')
else
replacement
|> Some
else
None
)
None)
|> Option.defaultValue filePath
let applyDir pathMap (dirName : string) : string =
if dirName.EndsWith dirSepStr then apply pathMap dirName
let applyDir pathMap (dirName: string) : string =
if dirName.EndsWith dirSepStr then
apply pathMap dirName
else
let mapped = apply pathMap (dirName + dirSepStr)
mapped.TrimEnd (Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
mapped.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
namespace Internal.Utilities.Collections
namespace Internal.Utilities.Collections
open System.Collections
open System.Collections.Generic
/// Iterable functional collection with O(1) append-1 time. Useful for data structures where elements get added at the
/// end but the collection must occasionally be iterated. Iteration is slower and may allocate because
/// end but the collection must occasionally be iterated. Iteration is slower and may allocate because
/// a suffix of elements is stored in reverse order.
///
/// The type doesn't support structural hashing or comparison.
type internal QueueList<'T>(firstElementsIn:'T list, lastElementsRevIn: 'T list, numLastElementsIn: int) =
type internal QueueList<'T>(firstElementsIn: 'T list, lastElementsRevIn: 'T list, numLastElementsIn: int) =
let numFirstElements = List.length firstElementsIn
// Push the lastElementsRev onto the firstElements every so often.
let push = numLastElementsIn > numFirstElements / 5
// Compute the contents after pushing.
let firstElements = if push then List.append firstElementsIn (List.rev lastElementsRevIn) else firstElementsIn
let firstElements =
if push then
List.append firstElementsIn (List.rev lastElementsRevIn)
else
firstElementsIn
let lastElementsRev = if push then [] else lastElementsRevIn
let numLastElements = if push then 0 else numLastElementsIn
// Compute the last elements on demand.
let lastElements() = if push then [] else List.rev lastElementsRev
let lastElements () =
if push then
[]
else
List.rev lastElementsRev
static let empty = QueueList<'T>([], [], 0)
static member Empty : QueueList<'T> = empty
static member Empty: QueueList<'T> = empty
new (xs:'T list) = QueueList(xs,[],0)
member x.ToList() = if push then firstElements else List.append firstElements (lastElements())
new(xs: 'T list) = QueueList(xs, [], 0)
member x.ToList() =
if push then
firstElements
else
List.append firstElements (lastElements ())
member x.FirstElements = firstElements
member x.LastElements = lastElements()
member x.LastElements = lastElements ()
/// This operation is O(1), unless a push happens, which is rare.
member x.AppendOne(y) = QueueList(firstElements, y :: lastElementsRev, numLastElements+1)
member x.AppendOne(y) =
QueueList(firstElements, y :: lastElementsRev, numLastElements + 1)
member x.Append(ys:seq<_>) =
member x.Append(ys: seq<_>) =
let newElements = Seq.toList ys
let newLength = List.length newElements
let lastElementsRevIn = List.rev newElements @ lastElementsRev
QueueList(firstElements, lastElementsRevIn, numLastElementsIn + newLength)
// This operation is O(n) anyway, so executing ToList() here is OK
interface IEnumerable<'T> with
member x.GetEnumerator() : IEnumerator<'T> = (x.ToList() :> IEnumerable<_>).GetEnumerator()
interface IEnumerable<'T> with
member x.GetEnumerator() : IEnumerator<'T> =
(x.ToList() :> IEnumerable<_>).GetEnumerator()
interface IEnumerable with
member x.GetEnumerator() : IEnumerator = ((x :> IEnumerable<'T>).GetEnumerator() :> IEnumerator)
interface IEnumerable with
member x.GetEnumerator() : IEnumerator =
((x :> IEnumerable<'T>).GetEnumerator() :> IEnumerator)
module internal QueueList =
let empty<'T> : QueueList<'T> = QueueList<'T>.Empty
let ofSeq (x:seq<_>) = QueueList(List.ofSeq x)
let ofSeq (x: seq<_>) = QueueList(List.ofSeq x)
let rec iter f (x:QueueList<_>) = Seq.iter f x
let rec iter f (x: QueueList<_>) = Seq.iter f x
let rec map f (x:QueueList<_>) = ofSeq (Seq.map f x)
let rec map f (x: QueueList<_>) = ofSeq (Seq.map f x)
let rec exists f (x:QueueList<_>) = Seq.exists f x
let rec exists f (x: QueueList<_>) = Seq.exists f x
let rec filter f (x:QueueList<_>) = ofSeq (Seq.filter f x)
let rec filter f (x: QueueList<_>) = ofSeq (Seq.filter f x)
let rec foldBack f (x:QueueList<_>) acc = List.foldBack f x.FirstElements (List.foldBack f x.LastElements acc)
let rec foldBack f (x: QueueList<_>) acc =
List.foldBack f x.FirstElements (List.foldBack f x.LastElements acc)
let forall f (x:QueueList<_>) = Seq.forall f x
let forall f (x: QueueList<_>) = Seq.forall f x
let ofList (x:_ list) = QueueList(x)
let ofList (x: _ list) = QueueList(x)
let toList (x:QueueList<_>) = Seq.toList x
let toList (x: QueueList<_>) = Seq.toList x
let tryFind f (x:QueueList<_>) = Seq.tryFind f x
let tryFind f (x: QueueList<_>) = Seq.tryFind f x
let one x = QueueList [x]
let one x = QueueList [ x ]
let appendOne (x:QueueList<_>) y = x.AppendOne(y)
let appendOne (x: QueueList<_>) y = x.AppendOne(y)
let append (x:QueueList<_>) (ys:QueueList<_>) = x.Append(ys)
let append (x: QueueList<_>) (ys: QueueList<_>) = x.Append(ys)
......@@ -7,175 +7,244 @@ open FSharp.Core.OptimizedClosures
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module internal ResizeArray =
let length (arr: ResizeArray<'T>) = arr.Count
let length (arr: ResizeArray<'T>) = arr.Count
let get (arr: ResizeArray<'T>) (n: int) = arr[n]
let get (arr: ResizeArray<'T>) (n: int) = arr[n]
let set (arr: ResizeArray<'T>) (n: int) (x:'T) = arr[n] <- x
let set (arr: ResizeArray<'T>) (n: int) (x: 'T) = arr[n] <- x
let create (n: int) x = ResizeArray<_>(seq { for _ in 1 .. n -> x })
let create (n: int) x =
ResizeArray<_>(seq { for _ in 1..n -> x })
let init (n: int) (f: int -> 'T) = ResizeArray<_>(seq { for i in 0 .. n-1 -> f i })
let init (n: int) (f: int -> 'T) =
ResizeArray<_>(seq { for i in 0 .. n - 1 -> f i })
let blit (arr1: ResizeArray<'T>) start1 (arr2: ResizeArray<'T>) start2 len =
if start1 < 0 then invalidArg "start1" "index must be positive"
if start2 < 0 then invalidArg "start2" "index must be positive"
if len < 0 then invalidArg "len" "length must be positive"
if start1 + len > length arr1 then invalidArg "start1" "(start1+len) out of range"
if start2 + len > length arr2 then invalidArg "start2" "(start2+len) out of range"
for i = 0 to len - 1 do
arr2[start2+i] <- arr1[start1 + i]
if start1 < 0 then
invalidArg "start1" "index must be positive"
let concat (arrs: ResizeArray<'T> list) = ResizeArray<_>(seq { for arr in arrs do for x in arr do yield x })
if start2 < 0 then
invalidArg "start2" "index must be positive"
let append (arr1: ResizeArray<'T>) (arr2: ResizeArray<'T>) = concat [arr1; arr2]
if len < 0 then
invalidArg "len" "length must be positive"
if start1 + len > length arr1 then
invalidArg "start1" "(start1+len) out of range"
if start2 + len > length arr2 then
invalidArg "start2" "(start2+len) out of range"
for i = 0 to len - 1 do
arr2[start2 + i] <- arr1[start1 + i]
let concat (arrs: ResizeArray<'T> list) =
ResizeArray<_>(
seq {
for arr in arrs do
for x in arr do
yield x
}
)
let append (arr1: ResizeArray<'T>) (arr2: ResizeArray<'T>) = concat [ arr1; arr2 ]
let sub (arr: ResizeArray<'T>) start len =
if start < 0 then invalidArg "start" "index must be positive"
if len < 0 then invalidArg "len" "length must be positive"
if start + len > length arr then invalidArg "len" "length must be positive"
ResizeArray<_>(seq { for i in start .. start+len-1 -> arr[i] })
let fill (arr: ResizeArray<'T>) (start: int) (len: int) (x:'T) =
if start < 0 then invalidArg "start" "index must be positive"
if len < 0 then invalidArg "len" "length must be positive"
if start + len > length arr then invalidArg "len" "length must be positive"
for i = start to start + len - 1 do
if start < 0 then
invalidArg "start" "index must be positive"
if len < 0 then
invalidArg "len" "length must be positive"
if start + len > length arr then
invalidArg "len" "length must be positive"
ResizeArray<_>(seq { for i in start .. start + len - 1 -> arr[i] })
let fill (arr: ResizeArray<'T>) (start: int) (len: int) (x: 'T) =
if start < 0 then
invalidArg "start" "index must be positive"
if len < 0 then
invalidArg "len" "length must be positive"
if start + len > length arr then
invalidArg "len" "length must be positive"
for i = start to start + len - 1 do
arr[i] <- x
let copy (arr: ResizeArray<'T>) = ResizeArray<_>(arr)
let copy (arr: ResizeArray<'T>) = ResizeArray<_>(arr)
let toList (arr: ResizeArray<_>) =
let mutable res = []
for i = length arr - 1 downto 0 do
res <- arr[i] :: res
res
let ofList (l: _ list) =
let len = l.Length
let res = ResizeArray<_>(len)
let rec add = function
| [] -> ()
| e :: l -> res.Add(e); add l
let rec add =
function
| [] -> ()
| e :: l ->
res.Add(e)
add l
add l
res
let iter f (arr: ResizeArray<_>) =
let iter f (arr: ResizeArray<_>) =
for i = 0 to arr.Count - 1 do
f arr[i]
let map f (arr: ResizeArray<_>) =
let len = length arr
let res = ResizeArray<_>(len)
for i = 0 to len - 1 do
res.Add(f arr[i])
res
let mapi f (arr: ResizeArray<_>) =
let f = FSharpFunc<_,_,_>.Adapt(f)
let f = FSharpFunc<_, _, _>.Adapt (f)
let len = length arr
let res = ResizeArray<_>(len)
for i = 0 to len - 1 do
res.Add(f.Invoke(i, arr[i]))
res
let iteri f (arr: ResizeArray<_>) =
let f = FSharpFunc<_,_,_>.Adapt(f)
let f = FSharpFunc<_, _, _>.Adapt (f)
for i = 0 to arr.Count - 1 do
f.Invoke(i, arr[i])
let exists (f: 'T -> bool) (arr: ResizeArray<'T>) =
let len = length arr
let rec loop i = i < len && (f arr[i] || loop (i+1))
let len = length arr
let rec loop i = i < len && (f arr[i] || loop (i + 1))
loop 0
let forall f (arr: ResizeArray<_>) =
let len = length arr
let rec loop i = i >= len || (f arr[i] && loop (i+1))
let rec loop i = i >= len || (f arr[i] && loop (i + 1))
loop 0
let indexNotFound() = raise (System.Collections.Generic.KeyNotFoundException("An index satisfying the predicate was not found in the collection"))
let indexNotFound () =
raise (System.Collections.Generic.KeyNotFoundException("An index satisfying the predicate was not found in the collection"))
let find f (arr: ResizeArray<_>) =
let rec loop i =
if i >= length arr then indexNotFound()
let find f (arr: ResizeArray<_>) =
let rec loop i =
if i >= length arr then indexNotFound ()
elif f arr[i] then arr[i]
else loop (i+1)
else loop (i + 1)
loop 0
let tryPick f (arr: ResizeArray<_>) =
let rec loop i =
if i >= length arr then None else
match f arr[i] with
| None -> loop(i+1)
| res -> res
let rec loop i =
if i >= length arr then
None
else
match f arr[i] with
| None -> loop (i + 1)
| res -> res
loop 0
let tryFind f (arr: ResizeArray<_>) =
let rec loop i =
let tryFind f (arr: ResizeArray<_>) =
let rec loop i =
if i >= length arr then None
elif f arr[i] then Some arr[i]
else loop (i+1)
else loop (i + 1)
loop 0
let iter2 f (arr1: ResizeArray<'T>) (arr2: ResizeArray<'b>) =
let f = FSharpFunc<_,_,_>.Adapt(f)
let iter2 f (arr1: ResizeArray<'T>) (arr2: ResizeArray<'b>) =
let f = FSharpFunc<_, _, _>.Adapt (f)
let len1 = length arr1
if len1 <> length arr2 then invalidArg "arr2" "the arrays have different lengths"
for i = 0 to len1 - 1 do
if len1 <> length arr2 then
invalidArg "arr2" "the arrays have different lengths"
for i = 0 to len1 - 1 do
f.Invoke(arr1[i], arr2[i])
let map2 f (arr1: ResizeArray<'T>) (arr2: ResizeArray<'b>) =
let f = FSharpFunc<_,_,_>.Adapt(f)
let map2 f (arr1: ResizeArray<'T>) (arr2: ResizeArray<'b>) =
let f = FSharpFunc<_, _, _>.Adapt (f)
let len1 = length arr1
if len1 <> length arr2 then invalidArg "arr2" "the arrays have different lengths"
if len1 <> length arr2 then
invalidArg "arr2" "the arrays have different lengths"
let res = ResizeArray<_>(len1)
for i = 0 to len1 - 1 do
res.Add(f.Invoke(arr1[i], arr2[i]))
res
let choose f (arr: ResizeArray<_>) =
let res = ResizeArray<_>()
let choose f (arr: ResizeArray<_>) =
let res = ResizeArray<_>()
for i = 0 to length arr - 1 do
match f arr[i] with
match f arr[i] with
| None -> ()
| Some b -> res.Add(b)
res
let filter f (arr: ResizeArray<_>) =
let res = ResizeArray<_>()
for i = 0 to length arr - 1 do
let x = arr[i]
let filter f (arr: ResizeArray<_>) =
let res = ResizeArray<_>()
for i = 0 to length arr - 1 do
let x = arr[i]
if f x then res.Add(x)
res
let partition f (arr: ResizeArray<_>) =
let res1 = ResizeArray<_>()
let res2 = ResizeArray<_>()
for i = 0 to length arr - 1 do
let x = arr[i]
if f x then res1.Add(x) else res2.Add(x)
res1, res2
let rev (arr: ResizeArray<_>) =
let len = length arr
let res = ResizeArray<_>(len)
for i = len - 1 downto 0 do
res.Add(arr[i])
res
let foldBack (f : 'T -> 'State -> 'State) (arr: ResizeArray<'T>) (acc: 'State) =
let mutable res = acc
let len = length arr
for i = len - 1 downto 0 do
let partition f (arr: ResizeArray<_>) =
let res1 = ResizeArray<_>()
let res2 = ResizeArray<_>()
for i = 0 to length arr - 1 do
let x = arr[i]
if f x then res1.Add(x) else res2.Add(x)
res1, res2
let rev (arr: ResizeArray<_>) =
let len = length arr
let res = ResizeArray<_>(len)
for i = len - 1 downto 0 do
res.Add(arr[i])
res
let foldBack (f: 'T -> 'State -> 'State) (arr: ResizeArray<'T>) (acc: 'State) =
let mutable res = acc
let len = length arr
for i = len - 1 downto 0 do
res <- f (get arr i) res
res
let fold (f : 'State -> 'T -> 'State) (acc: 'State) (arr: ResizeArray<'T>) =
let mutable res = acc
let len = length arr
for i = 0 to len - 1 do
let fold (f: 'State -> 'T -> 'State) (acc: 'State) (arr: ResizeArray<'T>) =
let mutable res = acc
let len = length arr
for i = 0 to len - 1 do
res <- f res (get arr i)
res
let toArray (arr: ResizeArray<'T>) = arr.ToArray()
......@@ -184,109 +253,155 @@ module internal ResizeArray =
let toSeq (arr: ResizeArray<'T>) = Seq.readonly arr
let sort f (arr: ResizeArray<'T>) = arr.Sort (System.Comparison(f))
let sortBy f (arr: ResizeArray<'T>) = arr.Sort (System.Comparison(fun x y -> compare (f x) (f y)))
let sort f (arr: ResizeArray<'T>) = arr.Sort(System.Comparison(f))
let sortBy f (arr: ResizeArray<'T>) =
arr.Sort(System.Comparison(fun x y -> compare (f x) (f y)))
let exists2 f (arr1: ResizeArray<_>) (arr2: ResizeArray<_>) =
let len1 = length arr1
if len1 <> length arr2 then invalidArg "arr2" "the arrays have different lengths"
let rec loop i = i < len1 && (f arr1[i] arr2[i] || loop (i+1))
if len1 <> length arr2 then
invalidArg "arr2" "the arrays have different lengths"
let rec loop i =
i < len1 && (f arr1[i] arr2[i] || loop (i + 1))
loop 0
let findIndex f (arr: ResizeArray<_>) =
let rec go n = if n >= length arr then indexNotFound() elif f arr[n] then n else go (n+1)
let rec go n =
if n >= length arr then indexNotFound ()
elif f arr[n] then n
else go (n + 1)
go 0
let findIndexi f (arr: ResizeArray<_>) =
let rec go n = if n >= length arr then indexNotFound() elif f n arr[n] then n else go (n+1)
let rec go n =
if n >= length arr then indexNotFound ()
elif f n arr[n] then n
else go (n + 1)
go 0
let foldSub f acc (arr: ResizeArray<_>) start fin =
let foldSub f acc (arr: ResizeArray<_>) start fin =
let mutable res = acc
for i = start to fin do
res <- f res arr[i]
res <- f res arr[i]
res
let foldBackSub f (arr: ResizeArray<_>) start fin acc =
let mutable res = acc
let foldBackSub f (arr: ResizeArray<_>) start fin acc =
let mutable res = acc
for i = fin downto start do
res <- f arr[i] res
res
let reduce f (arr : ResizeArray<_>) =
let reduce f (arr: ResizeArray<_>) =
let arrn = length arr
if arrn = 0 then invalidArg "arr" "the input array may not be empty"
else foldSub f arr[0] arr 1 (arrn - 1)
let reduceBack f (arr: ResizeArray<_>) =
if arrn = 0 then
invalidArg "arr" "the input array may not be empty"
else
foldSub f arr[0] arr 1 (arrn - 1)
let reduceBack f (arr: ResizeArray<_>) =
let arrn = length arr
if arrn = 0 then invalidArg "arr" "the input array may not be empty"
else foldBackSub f arr 0 (arrn - 2) arr[arrn - 1]
if arrn = 0 then
invalidArg "arr" "the input array may not be empty"
else
foldBackSub f arr 0 (arrn - 2) arr[arrn - 1]
let fold2 f (acc: 'T) (arr1: ResizeArray<'T1>) (arr2: ResizeArray<'T2>) =
let f = FSharpFunc<_,_,_,_>.Adapt(f)
let mutable res = acc
let f = FSharpFunc<_, _, _, _>.Adapt (f)
let mutable res = acc
let len = length arr1
if len <> length arr2 then invalidArg "arr2" "the arrays have different lengths"
if len <> length arr2 then
invalidArg "arr2" "the arrays have different lengths"
for i = 0 to len - 1 do
res <- f.Invoke(res,arr1[i],arr2[i])
res <- f.Invoke(res, arr1[i], arr2[i])
res
let foldBack2 f (arr1: ResizeArray<'T1>) (arr2: ResizeArray<'T2>) (acc: 'b) =
let f = FSharpFunc<_,_,_,_>.Adapt(f)
let mutable res = acc
let f = FSharpFunc<_, _, _, _>.Adapt (f)
let mutable res = acc
let len = length arr1
if len <> length arr2 then invalidArg "arr2" "the arrays have different lengths"
for i = len - 1 downto 0 do
res <- f.Invoke(arr1[i],arr2[i],res)
if len <> length arr2 then
invalidArg "arr2" "the arrays have different lengths"
for i = len - 1 downto 0 do
res <- f.Invoke(arr1[i], arr2[i], res)
res
let forall2 f (arr1: ResizeArray<_>) (arr2: ResizeArray<_>) =
let forall2 f (arr1: ResizeArray<_>) (arr2: ResizeArray<_>) =
let len1 = length arr1
if len1 <> length arr2 then invalidArg "arr2" "the arrays have different lengths"
let rec loop i = i >= len1 || (f arr1[i] arr2[i] && loop (i+1))
if len1 <> length arr2 then
invalidArg "arr2" "the arrays have different lengths"
let rec loop i =
i >= len1 || (f arr1[i] arr2[i] && loop (i + 1))
loop 0
let isEmpty (arr: ResizeArray<_>) = length (arr: ResizeArray<_>) = 0
let iteri2 f (arr1: ResizeArray<'T>) (arr2: ResizeArray<'b>) =
let f = FSharpFunc<_,_,_,_>.Adapt(f)
let f = FSharpFunc<_, _, _, _>.Adapt (f)
let len1 = length arr1
if len1 <> length arr2 then invalidArg "arr2" "the arrays have different lengths"
for i = 0 to len1 - 1 do
f.Invoke(i,arr1[i], arr2[i])
let mapi2 (f: int -> 'T -> 'b -> 'c) (arr1: ResizeArray<'T>) (arr2: ResizeArray<'b>) =
let f = FSharpFunc<_,_,_,_>.Adapt(f)
if len1 <> length arr2 then
invalidArg "arr2" "the arrays have different lengths"
for i = 0 to len1 - 1 do
f.Invoke(i, arr1[i], arr2[i])
let mapi2 (f: int -> 'T -> 'b -> 'c) (arr1: ResizeArray<'T>) (arr2: ResizeArray<'b>) =
let f = FSharpFunc<_, _, _, _>.Adapt (f)
let len1 = length arr1
if len1 <> length arr2 then invalidArg "arr2" "the arrays have different lengths"
if len1 <> length arr2 then
invalidArg "arr2" "the arrays have different lengths"
init len1 (fun i -> f.Invoke(i, arr1[i], arr2[i]))
let scanBackSub f (arr: ResizeArray<'T>) start fin acc =
let f = FSharpFunc<_,_,_>.Adapt(f)
let scanBackSub f (arr: ResizeArray<'T>) start fin acc =
let f = FSharpFunc<_, _, _>.Adapt (f)
let mutable state = acc
let res = create (2+fin-start) acc
let res = create (2 + fin - start) acc
for i = fin downto start do
state <- f.Invoke(arr[i], state)
res[i - start] <- state
res
let scanSub f acc (arr : ResizeArray<'T>) start fin =
let f = FSharpFunc<_,_,_>.Adapt(f)
let scanSub f acc (arr: ResizeArray<'T>) start fin =
let f = FSharpFunc<_, _, _>.Adapt (f)
let mutable state = acc
let res = create (fin-start+2) acc
let res = create (fin - start + 2) acc
for i = start to fin do
state <- f.Invoke(state, arr[i])
res[i - start+1] <- state
res[i - start + 1] <- state
res
let scan f acc (arr : ResizeArray<'T>) =
let scan f acc (arr: ResizeArray<'T>) =
let arrn = length arr
scanSub f acc arr 0 (arrn - 1)
let scanBack f (arr : ResizeArray<'T>) acc =
let scanBack f (arr: ResizeArray<'T>) acc =
let arrn = length arr
scanBackSub f arr 0 (arrn - 1) acc
......@@ -295,27 +410,38 @@ module internal ResizeArray =
res.Add(x)
res
let tryFindIndex f (arr: ResizeArray<'T>) =
let rec go n = if n >= length arr then None elif f arr[n] then Some n else go (n+1)
let tryFindIndex f (arr: ResizeArray<'T>) =
let rec go n =
if n >= length arr then None
elif f arr[n] then Some n
else go (n + 1)
go 0
let tryFindIndexi f (arr: ResizeArray<'T>) =
let rec go n = if n >= length arr then None elif f n arr[n] then Some n else go (n+1)
let tryFindIndexi f (arr: ResizeArray<'T>) =
let rec go n =
if n >= length arr then None
elif f n arr[n] then Some n
else go (n + 1)
go 0
let zip (arr1: ResizeArray<_>) (arr2: ResizeArray<_>) =
let len1 = length arr1
if len1 <> length arr2 then invalidArg "arr2" "the arrays have different lengths"
let zip (arr1: ResizeArray<_>) (arr2: ResizeArray<_>) =
let len1 = length arr1
if len1 <> length arr2 then
invalidArg "arr2" "the arrays have different lengths"
init len1 (fun i -> arr1[i], arr2[i])
let unzip (arr: ResizeArray<_>) =
let unzip (arr: ResizeArray<_>) =
let len = length arr
let res1 = ResizeArray<_>(len)
let res2 = ResizeArray<_>(len)
for i = 0 to len - 1 do
let x,y = arr[i]
for i = 0 to len - 1 do
let x, y = arr[i]
res1.Add(x)
res2.Add(y)
res1,res2
res1, res2
......@@ -10,14 +10,20 @@ module internal RidHelpers =
// Where rid is: win, win-x64, win-x86, osx-x64, linux-x64 etc ...
let probingRids, baseRid, platformRid =
let processArchitecture = RuntimeInformation.ProcessArchitecture
let baseRid =
if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then "win"
elif RuntimeInformation.IsOSPlatform(OSPlatform.OSX) then "osx"
else "linux"
if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
"win"
elif RuntimeInformation.IsOSPlatform(OSPlatform.OSX) then
"osx"
else
"linux"
let platformRid =
match processArchitecture with
| Architecture.X64 -> baseRid + "-x64"
| Architecture.X64 -> baseRid + "-x64"
| Architecture.X86 -> baseRid + "-x86"
| Architecture.Arm64 -> baseRid + "-arm64"
| _ -> baseRid + "-arm"
[| "any"; baseRid; platformRid |], baseRid, platformRid
......@@ -7,12 +7,11 @@ let s_escapeChars = [| '<'; '>'; '\"'; '\''; '&' |]
let getEscapeSequence c =
match c with
| '<' -> "&lt;"
| '>' -> "&gt;"
| '<' -> "&lt;"
| '>' -> "&gt;"
| '\"' -> "&quot;"
| '\'' -> "&apos;"
| '&' -> "&amp;"
| '&' -> "&amp;"
| _ as ch -> ch.ToString()
let escape str = String.collect getEscapeSequence str
......@@ -2,21 +2,44 @@
/// Configurable Diagnostics channel for the Abstract IL library
module internal FSharp.Compiler.AbstractIL.Diagnostics
module internal FSharp.Compiler.AbstractIL.Diagnostics
let mutable diagnosticsLog = Some stdout
let setDiagnosticsChannel s = diagnosticsLog <- s
let dflushn () = match diagnosticsLog with None -> () | Some d -> d.WriteLine(); d.Flush()
let dflush () = match diagnosticsLog with None -> () | Some d -> d.Flush()
let dprintn (s:string) =
match diagnosticsLog with None -> () | Some d -> d.Write s; d.Write "\n"; dflush()
let dprintf (fmt: Format<_,_,_,_>) =
Printf.kfprintf dflush (match diagnosticsLog with None -> System.IO.TextWriter.Null | Some d -> d) fmt
let dprintfn (fmt: Format<_,_,_,_>) =
Printf.kfprintf dflushn (match diagnosticsLog with None -> System.IO.TextWriter.Null | Some d -> d) fmt
let setDiagnosticsChannel s = diagnosticsLog <- s
let dflushn () =
match diagnosticsLog with
| None -> ()
| Some d ->
d.WriteLine()
d.Flush()
let dflush () =
match diagnosticsLog with
| None -> ()
| Some d -> d.Flush()
let dprintn (s: string) =
match diagnosticsLog with
| None -> ()
| Some d ->
d.Write s
d.Write "\n"
dflush ()
let dprintf (fmt: Format<_, _, _, _>) =
Printf.kfprintf
dflush
(match diagnosticsLog with
| None -> System.IO.TextWriter.Null
| Some d -> d)
fmt
let dprintfn (fmt: Format<_, _, _, _>) =
Printf.kfprintf
dflushn
(match diagnosticsLog with
| None -> System.IO.TextWriter.Null
| Some d -> d)
fmt
此差异已折叠。
此差异已折叠。
......@@ -5,62 +5,77 @@ module internal Internal.Utilities.Rational
open System.Numerics
type Rational = {
numerator: BigInteger
denominator: BigInteger
}
type Rational =
{
numerator: BigInteger
denominator: BigInteger
}
let rec gcd a (b: BigInteger) =
if b = BigInteger.Zero then a else
gcd b (a % b)
let lcm a b =
(a * b) / (gcd a b)
if b = BigInteger.Zero then
a
else
gcd b (a % b)
let lcm a b = (a * b) / (gcd a b)
let mkRational p q =
let p, q =
if q = BigInteger.Zero then raise(System.DivideByZeroException())
let g = gcd q p in
p/g, q/g
let p, q =
if q > BigInteger.Zero then p, q else -p, -q
in
{ numerator = p
denominator = q
}
let p, q =
if q = BigInteger.Zero then
raise (System.DivideByZeroException())
let g = gcd q p in
p / g, q / g
let p, q =
if q > BigInteger.Zero then
p, q
else
-p, -q
in
{ numerator = p; denominator = q }
let intToRational (p: int) =
mkRational (BigInteger(p)) BigInteger.One
let intToRational (p:int) = mkRational (BigInteger(p)) BigInteger.One
let ZeroRational = mkRational BigInteger.Zero BigInteger.One
let OneRational = mkRational BigInteger.One BigInteger.One
let AddRational m n =
let d = gcd m.denominator n.denominator
let m' = m.denominator / d
let n' = n.denominator / d
mkRational (m.numerator * n' + n.numerator * m') (m.denominator * n')
let d = gcd m.denominator n.denominator
let m' = m.denominator / d
let n' = n.denominator / d
mkRational (m.numerator * n' + n.numerator * m') (m.denominator * n')
let NegRational m =
mkRational (-m.numerator) m.denominator
let NegRational m = mkRational (-m.numerator) m.denominator
let MulRational m n =
mkRational (m.numerator * n.numerator) (m.denominator * n.denominator)
mkRational (m.numerator * n.numerator) (m.denominator * n.denominator)
let DivRational m n =
mkRational (m.numerator * n.denominator) (m.denominator * n.numerator)
mkRational (m.numerator * n.denominator) (m.denominator * n.numerator)
let AbsRational m =
mkRational (abs m.numerator) m.denominator
let AbsRational m =
mkRational (abs m.numerator) m.denominator
let RationalToString m =
if m.denominator = BigInteger.One then m.numerator.ToString() else sprintf "(%A/%A)" m.numerator m.denominator
if m.denominator = BigInteger.One then
m.numerator.ToString()
else
sprintf "(%A/%A)" m.numerator m.denominator
let GcdRational m n = mkRational (gcd m.numerator n.numerator) (lcm m.denominator n.denominator)
let GcdRational m n =
mkRational (gcd m.numerator n.numerator) (lcm m.denominator n.denominator)
let GetNumerator p = int p.numerator
let GetDenominator p = int p.denominator
let SignRational p =
if p.numerator < BigInteger.Zero then -1 else
if p.numerator > BigInteger.Zero then 1 else 0
let SignRational p =
if p.numerator < BigInteger.Zero then
-1
else if p.numerator > BigInteger.Zero then
1
else
0
此差异已折叠。
此差异已折叠。
......@@ -6,41 +6,49 @@ open Internal.Utilities.Collections.Tagged
open System.Collections.Generic
/// Maps with a specific comparison function
type internal Zmap<'Key,'T> = Internal.Utilities.Collections.Tagged.Map<'Key,'T>
type internal Zmap<'Key, 'T> = Internal.Utilities.Collections.Tagged.Map<'Key, 'T>
module internal Zmap =
module internal Zmap =
let empty (ord: IComparer<'T>) = Map<_,_,_>.Empty(ord)
let empty (ord: IComparer<'T>) = Map<_, _, _>.Empty (ord)
let add k v (m: Zmap<_,_>) = m.Add(k,v)
let find k (m: Zmap<_,_>) = m[k]
let tryFind k (m: Zmap<_,_>) = m.TryFind(k)
let remove k (m: Zmap<_,_>) = m.Remove(k)
let mem k (m: Zmap<_,_>) = m.ContainsKey(k)
let iter action (m: Zmap<_,_>) = m.Iterate(action)
let first f (m: Zmap<_,_>) = m.First(fun k v -> if f k v then Some (k,v) else None)
let exists f (m: Zmap<_,_>) = m.Exists(f)
let forall f (m: Zmap<_,_>) = m.ForAll(f)
let map mapping (m: Zmap<_,_>) = m.MapRange(mapping)
let mapi mapping (m: Zmap<_,_>) = m.Map(mapping)
let fold f (m: Zmap<_,_>) x = m.Fold f x
let toList (m: Zmap<_,_>) = m.ToList()
let foldSection lo hi f (m: Zmap<_,_>) x = m.FoldSection lo hi f x
let add k v (m: Zmap<_, _>) = m.Add(k, v)
let find k (m: Zmap<_, _>) = m[k]
let tryFind k (m: Zmap<_, _>) = m.TryFind(k)
let remove k (m: Zmap<_, _>) = m.Remove(k)
let mem k (m: Zmap<_, _>) = m.ContainsKey(k)
let iter action (m: Zmap<_, _>) = m.Iterate(action)
let isEmpty (m: Zmap<_,_>) = m.IsEmpty
let first f (m: Zmap<_, _>) =
m.First(fun k v -> if f k v then Some(k, v) else None)
let foldMap f z (m: Zmap<_,_>) =
let m,z = m.FoldAndMap (fun k v z -> let z,v' = f z k v in v',z) z in
z,m
let exists f (m: Zmap<_, _>) = m.Exists(f)
let forall f (m: Zmap<_, _>) = m.ForAll(f)
let map mapping (m: Zmap<_, _>) = m.MapRange(mapping)
let mapi mapping (m: Zmap<_, _>) = m.Map(mapping)
let fold f (m: Zmap<_, _>) x = m.Fold f x
let toList (m: Zmap<_, _>) = m.ToList()
let foldSection lo hi f (m: Zmap<_, _>) x = m.FoldSection lo hi f x
let choose f (m: Zmap<_,_>) = m.First(f)
let isEmpty (m: Zmap<_, _>) = m.IsEmpty
let chooseL f (m: Zmap<_,_>) =
m.Fold (fun k v s -> match f k v with None -> s | Some x -> x :: s) []
let foldMap f z (m: Zmap<_, _>) =
let m, z = m.FoldAndMap (fun k v z -> let z, v' = f z k v in v', z) z in z, m
let ofList ord xs = Internal.Utilities.Collections.Tagged.Map<_,_>.FromList(ord,xs)
let choose f (m: Zmap<_, _>) = m.First(f)
let keys (m: Zmap<_,_>) = m.Fold (fun k _ s -> k :: s) []
let values (m: Zmap<_,_>) = m.Fold (fun _ v s -> v :: s) []
let chooseL f (m: Zmap<_, _>) =
m.Fold
(fun k v s ->
match f k v with
| None -> s
| Some x -> x :: s)
[]
let ofList ord xs =
Internal.Utilities.Collections.Tagged.Map<_, _>.FromList (ord, xs)
let keys (m: Zmap<_, _>) = m.Fold (fun k _ s -> k :: s) []
let values (m: Zmap<_, _>) = m.Fold (fun _ v s -> v :: s) []
let memberOf m k = mem k m
......@@ -8,9 +8,10 @@ open System.Collections.Generic
/// Sets with a specific comparison function
type internal Zset<'T> = Internal.Utilities.Collections.Tagged.Set<'T>
module internal Zset =
module internal Zset =
let empty (ord : IComparer<'T>) = Internal.Utilities.Collections.Tagged.Set<_,_>.Empty(ord)
let empty (ord: IComparer<'T>) =
Internal.Utilities.Collections.Tagged.Set<_, _>.Empty (ord)
let isEmpty (s: Zset<_>) = s.IsEmpty
......@@ -19,33 +20,37 @@ module internal Zset =
let add x (s: Zset<_>) = s.Add(x)
let addList xs a = List.fold (fun a x -> add x a) a xs
let singleton ord x = add x (empty ord)
let remove x (s: Zset<_>) = s.Remove(x)
let fold (f : 'T -> 'b -> 'b) (s: Zset<_>) b = s.Fold f b
let fold (f: 'T -> 'b -> 'b) (s: Zset<_>) b = s.Fold f b
let iter f (s: Zset<_>) = s.Iterate f
let iter f (s: Zset<_>) = s.Iterate f
let forall predicate (s: Zset<_>) = s.ForAll predicate
let forall predicate (s: Zset<_>) = s.ForAll predicate
let count (s: Zset<_>) = s.Count
let count (s: Zset<_>) = s.Count
let exists predicate (s: Zset<_>) = s.Exists predicate
let subset (s1: Zset<_>) (s2: Zset<_>) = s1.IsSubsetOf s2
let subset (s1: Zset<_>) (s2: Zset<_>) = s1.IsSubsetOf s2
let equal (s1: Zset<_>) (s2: Zset<_>) = Internal.Utilities.Collections.Tagged.Set<_,_>.Equality(s1,s2)
let equal (s1: Zset<_>) (s2: Zset<_>) =
Internal.Utilities.Collections.Tagged.Set<_, _>.Equality (s1, s2)
let elements (s: Zset<_>) = s.ToList()
let filter predicate (s: Zset<_>) = s.Filter predicate
let union (s1: Zset<_>) (s2: Zset<_>) = Internal.Utilities.Collections.Tagged.Set<_,_>.Union(s1,s2)
let union (s1: Zset<_>) (s2: Zset<_>) =
Internal.Utilities.Collections.Tagged.Set<_, _>.Union (s1, s2)
let inter (s1: Zset<_>) (s2: Zset<_>) = Internal.Utilities.Collections.Tagged.Set<_,_>.Intersection(s1,s2)
let inter (s1: Zset<_>) (s2: Zset<_>) =
Internal.Utilities.Collections.Tagged.Set<_, _>.Intersection (s1, s2)
let diff (s1: Zset<_>) (s2: Zset<_>) = Internal.Utilities.Collections.Tagged.Set<_,_>.Difference(s1,s2)
let diff (s1: Zset<_>) (s2: Zset<_>) =
Internal.Utilities.Collections.Tagged.Set<_, _>.Difference (s1, s2)
let memberOf m k = contains k m
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册