diff --git a/src/Fable.Transforms/Fable2Babel.fs b/src/Fable.Transforms/Fable2Babel.fs index 2c0bde600c..55ecb08743 100644 --- a/src/Fable.Transforms/Fable2Babel.fs +++ b/src/Fable.Transforms/Fable2Babel.fs @@ -283,7 +283,7 @@ module Reflection = | Fable.Array _ | Fable.Tuple _ -> libCall com ctx None "Util" "isArrayLike" [|com.TransformAsExpr(ctx, expr)|] | Fable.List _ -> - jsInstanceof (libValue com ctx "List" "LinkedList$1") expr + jsInstanceof (libValue com ctx "List" "FSharpList") expr | Fable.AnonymousRecordType _ -> warnAndEvalToFalse "anonymous records" | Fable.MetaType -> diff --git a/src/Fable.Transforms/Replacements.fs b/src/Fable.Transforms/Replacements.fs index 0148bf486e..3eb803c83e 100644 --- a/src/Fable.Transforms/Replacements.fs +++ b/src/Fable.Transforms/Replacements.fs @@ -1661,50 +1661,12 @@ let stringModule (com: ICompiler) (ctx: Context) r t (i: CallInfo) (_: Expr opti Helper.LibCall(com, "String", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some let seqModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = - let sort r returnType descending projection args genArg = - let compareFn = - let identExpr ident = - match projection with - | Some projection -> - let info = makeCallInfo None [IdentExpr ident] [] - Call(projection, info, genArg, None) - | None -> IdentExpr ident - let x = makeUniqueIdent ctx genArg "x" - let y = makeUniqueIdent ctx genArg "y" - let comparison = - let comparison = compare com ctx None (identExpr x) (identExpr y) - if descending - then makeUnOp None (Number Int32) comparison UnaryMinus - else comparison - Delegate([x; y], comparison, None) - Helper.LibCall(com, "Seq", "sortWith", returnType, compareFn::args, ?loc=r) |> Some - match i.CompiledName, args with | "Cast", [arg] -> Some arg // Erase - | ("Cache" | "ToArray"), [arg] -> toArray r t arg |> Some - | "OfList", [arg] -> toSeq t arg |> Some - | "ToList", _ -> Helper.LibCall(com, "List", "ofSeq", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | ("ChunkBySize" | "Permute" | "SplitInto") as meth, [arg1; arg2] -> - let arg2 = toArray r (Array Any) arg2 - let result = Helper.LibCall(com, "Array", Naming.lowerFirst meth, Any, [arg1; arg2]) - Helper.LibCall(com, "Seq", "ofArray", t, [result]) |> Some - // For Using we need to cast the argument to IDisposable - | "EnumerateUsing", [arg; f] -> - Helper.LibCall(com, "Seq", "enumerateUsing", t, [arg; f], i.SignatureArgTypes, ?loc=r) |> Some - | ("Sort" | "SortDescending" as meth), args -> - (genArg com ctx r 0 i.GenericArgs) |> sort r t (meth = "SortDescending") None args - | ("SortBy" | "SortByDescending" as meth), projection::args -> - (genArg com ctx r 1 i.GenericArgs) |> sort r t (meth = "SortByDescending") (Some projection) args - | ("GroupBy" | "CountBy" as meth), args -> - let meth = Naming.lowerFirst meth - let args = injectArg com ctx r "Map" meth i.GenericArgs args - Helper.LibCall(com, "Map", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some - | ("Distinct" | "DistinctBy" as meth), args -> + | ("Distinct" | "DistinctBy" | "Except" | "GroupBy" | "CountBy" as meth), args -> let meth = Naming.lowerFirst meth - let args = injectArg com ctx r "Set" meth i.GenericArgs args - Helper.LibCall(com, "Set", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some - | "TryExactlyOne", args -> - tryCoreOp com r t "Seq" "exactlyOne" args |> Some + let args = injectArg com ctx r "Seq2" meth i.GenericArgs args + Helper.LibCall(com, "Seq2", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some | meth, _ -> let meth = Naming.lowerFirst meth let args = injectArg com ctx r "Seq" meth i.GenericArgs args @@ -1860,19 +1822,16 @@ let arrayModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Ex newArray (makeIntConst 0) t |> Some | "IsEmpty", [ar] -> eq (get r (Number Int32) ar "length") (makeIntConst 0) |> Some - | "TryExactlyOne", args -> - tryCoreOp com r t "Array" "exactlyOne" args |> Some - // | "SortInPlace", args -> - // let _, thisArg = List.splitLast args - // let argTypes = List.take (List.length args) i.SignatureArgTypes - // let compareFn = (genArg com ctx r 0 i.GenericArgs) |> makeComparerFunction com ctx - // Helper.InstanceCall(thisArg, "sort", t, [compareFn], argTypes, ?loc=r) |> Some | "CopyTo", args -> copyToArray com r t i args | Patterns.DicContains nativeArrayFunctions meth, _ -> let args, thisArg = List.splitLast args let argTypes = List.take (List.length args) i.SignatureArgTypes Helper.InstanceCall(thisArg, meth, t, args, argTypes, ?loc=r) |> Some + | ("Distinct" | "DistinctBy" | "Except" | "GroupBy" | "CountBy" as meth), args -> + let meth = Naming.lowerFirst meth + let args = injectArg com ctx r "Seq2" meth i.GenericArgs args + Helper.LibCall(com, "Seq2", "Array_" + meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some | meth, _ -> let meth = Naming.lowerFirst meth let args = injectArg com ctx r "Array" meth i.GenericArgs args @@ -1905,8 +1864,10 @@ let listModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Exp // Use a cast to give it better chances of optimization (e.g. converting list // literals to arrays) after the beta reduction pass | "ToSeq", [x] -> toSeq t x |> Some - | "TryExactlyOne", args -> - tryCoreOp com r t "List" "exactlyOne" args |> Some + | ("Distinct" | "DistinctBy" | "Except" | "GroupBy" | "CountBy" as meth), args -> + let meth = Naming.lowerFirst meth + let args = injectArg com ctx r "Seq2" meth i.GenericArgs args + Helper.LibCall(com, "Seq2", "List_" + meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some | meth, _ -> let meth = Naming.lowerFirst meth let args = injectArg com ctx r "List" meth i.GenericArgs args diff --git a/src/Fable.Transforms/ReplacementsInject.fs b/src/Fable.Transforms/ReplacementsInject.fs index f102cea231..e4c4bc6067 100644 --- a/src/Fable.Transforms/ReplacementsInject.fs +++ b/src/Fable.Transforms/ReplacementsInject.fs @@ -3,16 +3,6 @@ module Fable.Transforms.ReplacementsInject let fableReplacementsModules = Map [ - "Seq", Map [ - "maxBy", (Types.comparer, 1) - "max", (Types.comparer, 0) - "minBy", (Types.comparer, 1) - "min", (Types.comparer, 0) - "sumBy", (Types.adder, 1) - "sum", (Types.adder, 0) - "averageBy", (Types.averager, 1) - "average", (Types.averager, 0) - ] "Array", Map [ "append", (Types.arrayCons, 0) "mapIndexed", (Types.arrayCons, 1) @@ -25,12 +15,7 @@ let fableReplacementsModules = "mapFoldBack", (Types.arrayCons, 2) "concat", (Types.arrayCons, 0) "collect", (Types.arrayCons, 1) - "countBy", (Types.equalityComparer, 1) - "distinctBy", (Types.equalityComparer, 1) - "distinct", (Types.equalityComparer, 0) "contains", (Types.equalityComparer, 0) - "except", (Types.equalityComparer, 0) - "groupBy", (Types.equalityComparer, 1) "singleton", (Types.arrayCons, 0) "initialize", (Types.arrayCons, 0) "replicate", (Types.arrayCons, 0) @@ -60,7 +45,6 @@ let fableReplacementsModules = ] "List", Map [ "contains", (Types.equalityComparer, 0) - "except", (Types.equalityComparer, 0) "sort", (Types.comparer, 0) "sortBy", (Types.comparer, 1) "sortDescending", (Types.comparer, 0) @@ -73,14 +57,9 @@ let fableReplacementsModules = "min", (Types.comparer, 0) "average", ("Fable.Core.IGenericAverager`1", 0) "averageBy", ("Fable.Core.IGenericAverager`1", 1) - "distinctBy", (Types.equalityComparer, 1) - "distinct", (Types.equalityComparer, 0) - "groupBy", (Types.equalityComparer, 1) - "countBy", (Types.equalityComparer, 1) ] "Seq", Map [ "contains", (Types.equalityComparer, 0) - "except", (Types.equalityComparer, 0) "sort", (Types.comparer, 0) "sortBy", (Types.comparer, 1) "sortDescending", (Types.comparer, 0) @@ -94,6 +73,13 @@ let fableReplacementsModules = "average", ("Fable.Core.IGenericAverager`1", 0) "averageBy", ("Fable.Core.IGenericAverager`1", 1) ] + "Seq2", Map [ + "distinct", (Types.equalityComparer, 0) + "distinctBy", (Types.equalityComparer, 1) + "except", (Types.equalityComparer, 0) + "countBy", (Types.equalityComparer, 1) + "groupBy", (Types.equalityComparer, 1) + ] "Set", Map [ "FSharpSet__Map", (Types.comparer, 1) "singleton", (Types.comparer, 0) @@ -103,19 +89,11 @@ let fableReplacementsModules = "ofList", (Types.comparer, 0) "ofArray", (Types.comparer, 0) "ofSeq", (Types.comparer, 0) - "createMutable", (Types.equalityComparer, 0) - "distinct", (Types.equalityComparer, 0) - "distinctBy", (Types.equalityComparer, 1) "intersectWith", (Types.comparer, 0) "isSubsetOf", (Types.comparer, 0) "isSupersetOf", (Types.comparer, 0) "isProperSubsetOf", (Types.comparer, 0) "isProperSupersetOf", (Types.comparer, 0) ] - "Map", Map [ - "createMutable", (Types.equalityComparer, 0) - "groupBy", (Types.equalityComparer, 1) - "countBy", (Types.equalityComparer, 1) - ] ] diff --git a/src/fable-library/Array.fs b/src/fable-library/Array.fs index f99891fb18..c3b5ac56a0 100644 --- a/src/fable-library/Array.fs +++ b/src/fable-library/Array.fs @@ -254,28 +254,6 @@ let collect (mapping: 'T -> 'U[]) (array: 'T[]) ([] cons: Cons<'U>): 'U[ concat mapped cons // collectImpl mapping array // flatMap not widely available yet -let countBy (projection: 'T -> 'Key) (array: 'T[]) ([] eq: IEqualityComparer<'Key>): ('Key * int)[] = - let dict = Dictionary<'Key, int>(eq) - let keys: 'Key[] = [||] - for value in array do - let key = projection value - match dict.TryGetValue(key) with - | true, prev -> - dict.[key] <- prev + 1 - | false, _ -> - dict.[key] <- 1 - pushImpl keys key |> ignore - let result = - map (fun key -> key, dict.[key]) keys Unchecked.defaultof<_> - result - -let distinctBy (projection: 'T -> 'Key) (array: 'T[]) ([] eq: IEqualityComparer<'Key>) = - let hashSet = HashSet<'Key>(eq) - array |> filter (projection >> hashSet.Add) - -let distinct (array: 'T[]) ([] eq: IEqualityComparer<'T>) = - distinctBy id array eq - let where predicate (array: _[]) = filterImpl predicate array let contains<'T> (value: 'T) (array: 'T[]) ([] eq: IEqualityComparer<'T>) = @@ -287,28 +265,6 @@ let contains<'T> (value: 'T) (array: 'T[]) ([] eq: IEqualityComparer<'T> else loop (i + 1) loop 0 -let except (itemsToExclude: seq<'T>) (array: 'T[]) ([] eq: IEqualityComparer<'T>): 'T[] = - if array.Length = 0 then - array - else - let cached = HashSet(itemsToExclude, eq) - array |> filterImpl cached.Add - -let groupBy (projection: 'T -> 'Key) (array: 'T[]) ([] eq: IEqualityComparer<'Key>): ('Key * 'T[])[] = - let dict = Dictionary<'Key, ResizeArray<'T>>(eq) - let keys: 'Key[] = [||] - for v in array do - let key = projection v - match dict.TryGetValue(key) with - | true, prev -> - prev.Add(v) - | false, _ -> - dict.Add(key, ResizeArray [|v|]) - pushImpl keys key |> ignore - let result = - map (fun key -> key, arrayFrom dict.[key]) keys Unchecked.defaultof<_> - result - let empty cons = allocateArrayFromCons cons 0 let singleton value ([] cons: Cons<'T>) = @@ -414,7 +370,8 @@ let addInPlace (x: 'T) (array: 'T[]) = let addRangeInPlace (range: seq<'T>) (array: 'T[]) = // if isTypedArrayImpl array then invalidArg "array" "Typed arrays not supported" - Seq.iter (fun x -> pushImpl array x |> ignore) range + for x in range do + addInPlace x array let removeInPlace (item: 'T) (array: 'T[]) = // if isTypedArrayImpl array then invalidArg "array" "Typed arrays not supported" @@ -778,6 +735,11 @@ let exactlyOne (array: 'T[]) = elif array.Length = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString else invalidArg "array" "Input array too long" +let tryExactlyOne (array: 'T[]) = + if array.Length = 1 + then Some (array.[0]) + else None + let head (array: 'T[]) = if array.Length = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString else array.[0] diff --git a/src/fable-library/BigInt.fs b/src/fable-library/BigInt.fs index b027060830..c5c378d6a2 100644 --- a/src/fable-library/BigInt.fs +++ b/src/fable-library/BigInt.fs @@ -88,7 +88,7 @@ let private flipTwosComplement currByte lowBitFound = | 0uy, false -> 0uy, false // Haven't found first bit yet and no chance to do so with zero byte | _, false -> // Found first byte containing a 1, flip higher bits and all future bytes - let firstBitIndex = [0..7] |> List.find (fun i -> currByte &&& (1uy <<< i) > 0uy) + let firstBitIndex = [|0;1;2;3;4;5;6;7|] |> Array.find (fun i -> currByte &&& (1uy <<< i) > 0uy) (currByte ^^^ (0b11111110uy <<< firstBitIndex)) &&& 255uy, true // Spec: @@ -148,7 +148,7 @@ let fromByteArray (bytes:byte array) = |> fun value -> if isPositive then value else bigint(-1) * value else let bytesToProcess = min bytesRemaining 4 - for i in 0 .. bytesToProcess - 1 do buffer.[i] <- bytes.[currIndex + i] // fill buffer with up to 4 bytes + for i = 0 to bytesToProcess - 1 do buffer.[i] <- bytes.[currIndex + i] // fill buffer with up to 4 bytes if isPositive then Array.fill buffer bytesToProcess (4 - bytesToProcess) 0uy // clear any unfilled bytes in buffer let value = diff --git a/src/fable-library/Fable.Library.fsproj b/src/fable-library/Fable.Library.fsproj index 571e51e99d..8c638e193e 100644 --- a/src/fable-library/Fable.Library.fsproj +++ b/src/fable-library/Fable.Library.fsproj @@ -25,6 +25,7 @@ + diff --git a/src/fable-library/List.fs b/src/fable-library/List.fs index a016fe8597..dcf0a8e18a 100644 --- a/src/fable-library/List.fs +++ b/src/fable-library/List.fs @@ -13,7 +13,7 @@ module SR = let notEnoughElements = "The input sequence has an insufficient number of elements." [] -// [] +[] type LinkedList<'T when 'T: comparison> = { head: 'T; mutable tail: LinkedList<'T> option } @@ -471,12 +471,6 @@ let contains (value: 'T) (xs: 'T list) ([] eq: System.Collections.Generi tryFindIndex (fun v -> eq.Equals (value, v)) xs |> Option.isSome -let except (itemsToExclude: seq<'T>) (xs: 'T list) ([] eq: System.Collections.Generic.IEqualityComparer<'T>) = - if xs.IsEmpty then xs - else - let cached = System.Collections.Generic.HashSet(itemsToExclude, eq) - xs |> filter cached.Add - let initialize n (f: int -> 'T) = let root = List.Empty let mutable node = root @@ -525,7 +519,7 @@ let zip3 xs ys zs = let sortWith (comparer: 'T -> 'T -> int) (xs: 'T list) = let arr = toArray xs - Array.sortInPlaceWith comparer arr // TODO: use stable sort + Array.sortInPlaceWith comparer arr // Note: In JS this sort is stable arr |> ofArray let sort (xs: 'T list) ([] comparer: System.Collections.Generic.IComparer<'T>) = @@ -646,13 +640,6 @@ let splitAt index (xs: 'T list) = if index > xs.Length then invalidArg "index" SR.notEnoughElements take index xs, skip index xs -let distinctBy (projection: 'T -> 'Key) (xs: 'T list) ([] eq: System.Collections.Generic.IEqualityComparer<'Key>) = - let hashSet = System.Collections.Generic.HashSet<'Key>(eq) - xs |> filter (projection >> hashSet.Add) - -let distinct (xs: 'T list) ([] eq: System.Collections.Generic.IEqualityComparer<'T>) = - distinctBy id xs eq - let exactlyOne (xs: 'T list) = if xs.IsEmpty then invalidArg "list" SR.inputSequenceEmpty @@ -660,35 +647,10 @@ let exactlyOne (xs: 'T list) = if xs.Tail.IsEmpty then xs.Head else invalidArg "list" SR.inputSequenceTooLong -let groupBy (projection: 'T -> 'Key) (xs: 'T list) ([] eq: System.Collections.Generic.IEqualityComparer<'Key>): ('Key * 'T list) list = - let dict = System.Collections.Generic.Dictionary<'Key, 'T list>(eq) - let mutable keys = List.Empty - xs |> iterate (fun v -> - let key = projection v - match dict.TryGetValue(key) with - | true, prev -> - dict.[key] <- List.Cons(v, prev) - | false, _ -> - dict.Add(key, List.Cons(v, List.Empty)) - keys <- List.Cons(key, keys) ) - let mutable result = List.Empty - keys |> iterate (fun key -> result <- List.Cons((key, reverse dict.[key]), result)) - result - -let countBy (projection: 'T -> 'Key) (xs: 'T list) ([] eq: System.Collections.Generic.IEqualityComparer<'Key>) = - let dict = System.Collections.Generic.Dictionary<'Key, int>(eq) - let mutable keys = List.Empty - xs |> iterate (fun v -> - let key = projection v - match dict.TryGetValue(key) with - | true, prev -> - dict.[key] <- prev + 1 - | false, _ -> - dict.[key] <- 1 - keys <- List.Cons(key, keys) ) - let mutable result = List.Empty - keys |> iterate (fun key -> result <- List.Cons((key, dict.[key]), result)) - result +let tryExactlyOne (xs: 'T list) = + if not (xs.IsEmpty) && xs.Tail.IsEmpty + then Some (xs.Head) + else None let where predicate (xs: 'T list) = filter predicate xs @@ -712,7 +674,8 @@ let splitInto (chunks: int) (xs: 'T list): 'T list list = let transpose (lists: seq<'T list>): 'T list list = lists - |> Seq.map toArray + |> Array.ofSeq + |> Array.map toArray |> Array.transpose |> Array.map ofArray |> ofArray diff --git a/src/fable-library/Map.fs b/src/fable-library/Map.fs index a2de9c644e..892f83ce1e 100644 --- a/src/fable-library/Map.fs +++ b/src/fable-library/Map.fs @@ -877,34 +877,6 @@ let toArray (table: Map<_, _>) = let empty<'Key, 'Value when 'Key : comparison> = Map<'Key, 'Value>.Empty -let createMutable (source: KeyValuePair<'Key, 'Value> seq) ([] comparer: IEqualityComparer<'Key>) = - let map = Fable.Collections.MutableMap(source, comparer) - map :> Fable.Core.JS.Map<_,_> - -let groupBy (projection: 'T -> 'Key) (xs: 'T seq) ([] comparer: IEqualityComparer<'Key>): ('Key * 'T seq) seq = - let dict: Fable.Core.JS.Map<_,ResizeArray<'T>> = createMutable Seq.empty comparer - - // Build the groupings - for v in xs do - let key = projection v - if dict.has(key) then dict.get(key).Add(v) - else dict.set(key, ResizeArray [v]) |> ignore - - // Mapping shouldn't be necessary because KeyValuePair compiles - // as a tuple, but let's do it just in case the implementation changes - dict.entries() |> Seq.map (fun (k,v) -> k, upcast v) - -let countBy (projection: 'T -> 'Key) (xs: 'T seq) ([] comparer: IEqualityComparer<'Key>): ('Key * int) seq = - let dict = createMutable Seq.empty comparer - - for value in xs do - let key = projection value - if dict.has(key) then dict.set(key, dict.get(key) + 1) - else dict.set(key, 1) - |> ignore - - dict.entries() - // [] let count (table: Map<_, _>) = table.Count \ No newline at end of file diff --git a/src/fable-library/MutableMap.fs b/src/fable-library/MutableMap.fs index b4755c658f..c6b3c8264d 100644 --- a/src/fable-library/MutableMap.fs +++ b/src/fable-library/MutableMap.fs @@ -37,7 +37,10 @@ type MutableMap<'Key, 'Value when 'Key: equality>(pairs: KeyValuePair<'Key, 'Val hashMap.Clear() member this.Count = - hashMap.Values |> Seq.sumBy (fun pairs -> pairs.Count) + let mutable count = 0 + for pairs in hashMap.Values do + count <- count + pairs.Count + count member this.Item with get (k: 'Key) = diff --git a/src/fable-library/MutableSet.fs b/src/fable-library/MutableSet.fs index 8aa8d5f0f7..ce73b08aa0 100644 --- a/src/fable-library/MutableSet.fs +++ b/src/fable-library/MutableSet.fs @@ -37,7 +37,10 @@ type MutableSet<'T when 'T: equality>(items: 'T seq, comparer: IEqualityComparer hashMap.Clear() member this.Count = - hashMap.Values |> Seq.sumBy (fun pairs -> pairs.Count) + let mutable count = 0 + for items in hashMap.Values do + count <- count + items.Count + count member this.Add(k) = match this.TryFindIndex(k) with diff --git a/src/fable-library/Seq.fs b/src/fable-library/Seq.fs index 1835bd104e..6eedc388f8 100644 --- a/src/fable-library/Seq.fs +++ b/src/fable-library/Seq.fs @@ -25,6 +25,8 @@ module Enumerator = let notStarted() = raise (new System.InvalidOperationException(SR.enumerationNotStarted)) let alreadyFinished() = raise (new System.InvalidOperationException(SR.enumerationAlreadyFinished)) + [] + [] type Enumerable<'T>(f) = interface IEnumerable<'T> with member x.GetEnumerator() = f() @@ -43,6 +45,8 @@ module Enumerator = str <- str + "; ..." str + "]" + // // in JS using this object is slower than the object expression below + // // type FromFunctions<'T>(get, next, reset, dispose) = // interface IEnumerator<'T> with // member __.Current = get() @@ -66,7 +70,7 @@ module Enumerator = interface System.IDisposable with member __.Dispose() = dispose() } - // // for languages where arrays are not IEnumerable + // // implementation for languages where arrays are not IEnumerable // // let ofArray (arr: 'T[]): IEnumerator<'T> = // let len = arr.Length @@ -113,104 +117,30 @@ module Enumerator = | _ -> () fromFunctions get next reset dispose - let choose (f: int -> 'T -> 'U option) (e: IEnumerator<'T>): IEnumerator<'U> = - let mutable index = -1 - let mutable curr = None - let get() = - if index < 0 then notStarted() - match curr with - | None -> alreadyFinished() - | Some x -> x - let next() = - curr <- None - index <- index + 1 - while (Option.isNone curr && e.MoveNext()) do - curr <- f index e.Current - if Option.isNone curr then index <- index + 1 - let finished = Option.isNone curr - not finished - let reset() = noReset() - let dispose() = - try e.Dispose() - finally () - fromFunctions get next reset dispose - - let choose2 (f: int -> 'T1 -> 'T2 -> 'U option) (e1: IEnumerator<'T1>) (e2: IEnumerator<'T2>): IEnumerator<'U> = - let mutable index = -1 - let mutable curr = None - let get() = - if index < 0 then notStarted() - match curr with - | None -> alreadyFinished() - | Some x -> x - let next() = - curr <- None - index <- index + 1 - while (Option.isNone curr && e1.MoveNext() && e2.MoveNext()) do - curr <- f index e1.Current e2.Current - if Option.isNone curr then index <- index + 1 - let finished = Option.isNone curr - not finished - let reset() = noReset() - let dispose() = - try e1.Dispose() - finally - try e2.Dispose() - finally () - fromFunctions get next reset dispose - - let choose3 (f: int -> 'T1 -> 'T2 -> 'T3 -> 'U option) (e1: IEnumerator<'T1>) (e2: IEnumerator<'T2>) (e3: IEnumerator<'T3>): IEnumerator<'U> = - let mutable index = -1 - let mutable curr = None - let get() = - if index < 0 then notStarted() - match curr with - | None -> alreadyFinished() - | Some x -> x - let next() = - curr <- None - index <- index + 1 - while (Option.isNone curr && e1.MoveNext() && e2.MoveNext() && e3.MoveNext()) do - curr <- f index e1.Current e2.Current e3.Current - if Option.isNone curr then index <- index + 1 - let finished = Option.isNone curr - not finished - let reset() = noReset() - let dispose() = - try e1.Dispose() - finally - try e3.Dispose() - finally - try e3.Dispose() - finally () - fromFunctions get next reset dispose - let concat<'T,'U when 'U :> seq<'T>> (sources: seq<'U>) = let mutable outerOpt: IEnumerator<'U> option = None let mutable innerOpt: IEnumerator<'T> option = None let mutable started = false let mutable finished = false - let mutable currElement = None + let mutable curr = None let get() = if not started then notStarted() elif finished then alreadyFinished() - match currElement with + match curr with | None -> alreadyFinished() | Some x -> x let finish() = finished <- true - try - match innerOpt with - | None -> () - | Some inner -> - try inner.Dispose() - finally innerOpt <- None - finally - match outerOpt with - | None -> () - | Some outer -> - try outer.Dispose() - finally outerOpt <- None + match innerOpt with + | None -> () + | Some inner -> + try inner.Dispose() + finally innerOpt <- None + match outerOpt with + | None -> () + | Some outer -> + try outer.Dispose() + finally outerOpt <- None let loop () = let mutable res = None while Option.isNone res do @@ -226,7 +156,7 @@ module Enumerator = res <- Some false | Some _, Some inner -> if inner.MoveNext() then - currElement <- Some (inner.Current) + curr <- Some (inner.Current) res <- Some true else try inner.Dispose() @@ -240,6 +170,13 @@ module Enumerator = let dispose() = if not finished then finish() fromFunctions get next reset dispose + let enumerateThenFinally f (e: IEnumerator<'T>): IEnumerator<'T> = + let get() = e.Current + let next() = e.MoveNext() + let reset() = noReset() + let dispose() = try e.Dispose() finally f() + fromFunctions get next reset dispose + let generateWhileSome (openf: unit -> 'T) (compute: 'T -> 'U option) (closef: 'T -> unit): IEnumerator<'U> = let mutable started = false let mutable curr = None @@ -269,28 +206,6 @@ module Enumerator = | Some _ as x -> curr <- x; true fromFunctions get next reset dispose - let enumerateThenFinally f (e: IEnumerator<'T>): IEnumerator<'T> = - let get() = e.Current - let next() = e.MoveNext() - let reset() = noReset() - let dispose() = try e.Dispose() finally f() - fromFunctions get next reset dispose - - let map (f: 'T -> 'U) (e: IEnumerator<'T>): IEnumerator<'U> = - choose (fun _i x -> Some (f x)) e - - let mapi (f: int -> 'T -> 'U) (e: IEnumerator<'T>): IEnumerator<'U> = - choose (fun i x -> Some (f i x)) e - - let map2 (f: 'T1 -> 'T2 -> 'U) (e1: IEnumerator<'T1>) (e2: IEnumerator<'T2>): IEnumerator<'U> = - choose2 (fun _i x y -> Some (f x y)) e1 e2 - - let mapi2 (f: int -> 'T1 -> 'T2 -> 'U) (e1: IEnumerator<'T1>) (e2: IEnumerator<'T2>): IEnumerator<'U> = - choose2 (fun i x y -> Some (f i x y)) e1 e2 - - let map3 (f: 'T1 -> 'T2 -> 'T3 -> 'U) (e1: IEnumerator<'T1>) (e2: IEnumerator<'T2>) (e3: IEnumerator<'T3>): IEnumerator<'U> = - choose3 (fun _i x y z -> Some (f x y z)) e1 e2 e3 - let unfold (f: 'State -> ('T * 'State) option) (state: 'State): IEnumerator<'T> = let mutable curr: ('T * 'State) option = None let mutable acc: 'State = state @@ -309,6 +224,8 @@ module Enumerator = let dispose() = () fromFunctions get next reset dispose +// [] +// [] // module Seq = let indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.keyNotFoundAlt)) @@ -355,6 +272,18 @@ let empty () = let singleton x = delay (fun () -> (Array.singleton x) :> seq<'T>) // Enumerator.singleton x) +let generate create compute dispose = + mkSeq (fun () -> Enumerator.generateWhileSome create compute dispose) + +let generateIndexed create compute dispose = + mkSeq (fun () -> + let mutable i = -1 + Enumerator.generateWhileSome create (fun x -> i <- i + 1; compute i x) dispose + ) + +// let inline generateUsing (openf: unit -> ('U :> System.IDisposable)) compute = +// generate openf compute (fun (s: 'U) -> s.Dispose()) + let append (xs: seq<'T>) (ys: seq<'T>) = concat [| xs; ys |] @@ -365,11 +294,15 @@ let cast (xs: System.Collections.IEnumerable) = |> Enumerator.cast ) -let choose chooser (xs: seq<'T>) = - mkSeq (fun () -> - ofSeq xs - |> Enumerator.choose (fun _i x -> chooser x) - ) +let choose (chooser: 'T -> 'U option) (xs: seq<'T>) = + generate + (fun () -> ofSeq xs) + (fun e -> + let mutable curr = None + while (Option.isNone curr && e.MoveNext()) do + curr <- chooser e.Current + curr) + (fun e -> e.Dispose()) let compareWith (comparer: 'T -> 'T -> int) (xs: seq<'T>) (ys: seq<'T>): int = use e1 = ofSeq xs @@ -387,20 +320,20 @@ let compareWith (comparer: 'T -> 'T -> int) (xs: seq<'T>) (ys: seq<'T>): int = elif b2 then -1 else 0 -let contains (value: 'T) (xs: seq<'T>) ([] eq: System.Collections.Generic.IEqualityComparer<'T>) = +let contains (value: 'T) (xs: seq<'T>) ([] comparer: System.Collections.Generic.IEqualityComparer<'T>) = use e = ofSeq xs let mutable found = false while (not found && e.MoveNext()) do - found <- eq.Equals(value, e.Current) + found <- comparer.Equals(value, e.Current) found -let inline Generate openf compute closef = - mkSeq (fun () -> Enumerator.generateWhileSome openf compute closef) - -let inline GenerateUsing (openf: unit -> ('U :> System.IDisposable)) compute = - Generate openf compute (fun (s: 'U) -> s.Dispose()) +let enumerateFromFunctions create moveNext current = + generate + create + (fun x -> if moveNext x then Some(current x) else None) + (fun x -> match box(x) with :? System.IDisposable as id -> id.Dispose() | _ -> ()) -let inline FinallyEnumerable<'T> (compensation: unit -> unit, restf: unit -> seq<'T>) = +let inline finallyEnumerable<'T> (compensation: unit -> unit, restf: unit -> seq<'T>) = mkSeq (fun () -> try let e = restf() |> ofSeq @@ -410,28 +343,19 @@ let inline FinallyEnumerable<'T> (compensation: unit -> unit, restf: unit -> seq reraise() ) -let enumerateFromFunctions create moveNext current = - Generate - create - (fun x -> if moveNext x then Some(current x) else None) - (fun x -> match box(x) with :? System.IDisposable as id -> id.Dispose() | _ -> ()) - let enumerateThenFinally (source: seq<'T>) (compensation: unit -> unit) = - FinallyEnumerable(compensation, (fun () -> source)) + finallyEnumerable(compensation, (fun () -> source)) let enumerateUsing (resource: 'T :> System.IDisposable) (source: 'T -> #seq<'U>) = - FinallyEnumerable( + finallyEnumerable( (fun () -> match box resource with null -> () | _ -> resource.Dispose()), (fun () -> source resource :> seq<_>)) let enumerateWhile (guard: unit -> bool) (xs: seq<'T>) = concat (unfold (fun i -> if guard() then Some(xs, i + 1) else None) 0) -let except (itemsToExclude: seq<'T>) (xs: seq<'T>) ([] eq: System.Collections.Generic.IEqualityComparer<'T>) = - mkSeq (fun () -> - let hashSet = System.Collections.Generic.HashSet(itemsToExclude, eq) //, HashIdentity.Structural) - Enumerator.choose (fun _i x -> if hashSet.Add(x) then Some x else None) (ofSeq xs) - ) +let filter f (xs: seq<'T>) = + xs |> choose (fun x -> if f x then Some x else None) let exists predicate (xs: seq<'T>) = use e = ofSeq xs @@ -468,9 +392,6 @@ let tryExactlyOne (xs: seq<'T>) = else None -let filter f (xs: seq<'T>) = - xs |> choose (fun x -> if f x then Some x else None) - let tryFind predicate (xs: seq<'T>) = use e = ofSeq xs let mutable res = None @@ -541,20 +462,9 @@ let foldBack2 (folder: 'T1 -> 'T2 -> 'State -> 'State) (xs: seq<'T1>) (ys: seq<' Array.foldBack2 folder (toArray xs) (toArray ys) state let forAll predicate xs = - // use e = ofSeq xs - // let mutable ok = true - // while (ok && e.MoveNext()) do - // ok <- predicate e.Current - // ok not (exists (fun x -> not (predicate x)) xs) let forAll2 predicate xs ys = - // use e1 = ofSeq xs - // use e2 = ofSeq ys - // let mutable ok = true - // while (ok && e1.MoveNext() && e2.MoveNext()) do - // ok <- predicate e1.Current e2.Current - // ok not (exists2 (fun x y -> not (predicate x y)) xs ys) let tryHead (xs: seq<'T>) = @@ -572,12 +482,6 @@ let head (xs: seq<'T>) = | Some x -> x | None -> invalidArg "source" SR.inputSequenceEmpty -let indexed (xs: seq<'T>) = - mkSeq (fun () -> - ofSeq xs - |> Enumerator.mapi (fun i x -> (i, x)) - ) - let initialize count f = unfold (fun i -> if (i < count) then Some(f i, i + 1) else None) 0 @@ -649,39 +553,69 @@ let length (xs: seq<'T>) = count let map (mapping: 'T -> 'U) (xs: seq<'T>) = - mkSeq (fun () -> - ofSeq xs - |> Enumerator.map mapping - ) + generate + (fun () -> ofSeq xs) + (fun e -> if e.MoveNext() then Some (mapping e.Current) else None) + (fun e -> e.Dispose()) let mapIndexed (mapping: int -> 'T -> 'U) (xs: seq<'T>) = - mkSeq (fun () -> - ofSeq xs - |> Enumerator.mapi mapping - ) + generateIndexed + (fun () -> ofSeq xs) + (fun i e -> if e.MoveNext() then Some (mapping i e.Current) else None) + (fun e -> e.Dispose()) + +let indexed (xs: seq<'T>) = + xs |> mapIndexed (fun i x -> (i, x)) let map2 (mapping: 'T1 -> 'T2 -> 'U) (xs: seq<'T1>) (ys: seq<'T2>) = - mkSeq (fun () -> - (ofSeq xs, ofSeq ys) - ||> Enumerator.map2 mapping - ) + generate + (fun () -> (ofSeq xs, ofSeq ys)) + (fun (e1, e2) -> + if e1.MoveNext() && e2.MoveNext() + then Some (mapping e1.Current e2.Current) + else None) + (fun (e1, e2) -> try e1.Dispose() finally e2.Dispose()) let mapIndexed2 (mapping: int -> 'T1 -> 'T2 -> 'U) (xs: seq<'T1>) (ys: seq<'T2>) = - mkSeq (fun () -> - (ofSeq xs, ofSeq ys) - ||> Enumerator.mapi2 (fun i x y -> Some (mapping i x y)) - ) + generateIndexed + (fun () -> (ofSeq xs, ofSeq ys)) + (fun i (e1, e2) -> + if e1.MoveNext() && e2.MoveNext() + then Some (mapping i e1.Current e2.Current) + else None) + (fun (e1, e2) -> try e1.Dispose() finally e2.Dispose()) let map3 (mapping: 'T1 -> 'T2 -> 'T3 -> 'U) (xs: seq<'T1>) (ys: seq<'T2>) (zs: seq<'T3>) = - mkSeq (fun () -> - (ofSeq xs, ofSeq ys, ofSeq zs) - |||> Enumerator.map3 mapping - ) + generate + (fun () -> (ofSeq xs, ofSeq ys, ofSeq zs)) + (fun (e1, e2, e3) -> + if e1.MoveNext() && e2.MoveNext() && e3.MoveNext() + then Some (mapping e1.Current e2.Current e3.Current) + else None) + (fun (e1, e2, e3) -> try e1.Dispose() finally try e2.Dispose() finally e3.Dispose()) let readOnly (xs: seq<'T>) = checkNonNull "source" xs map id xs +let cache (xs: seq<'T>) = + let mutable cached = false + let xsCache = ResizeArray() + delay (fun () -> + if not cached then + cached <- true + xs |> map (fun x -> xsCache.Add(x); x) + else + xsCache :> seq<'T> + ) + +let allPairs (xs: seq<'T1>) (ys: seq<'T2>): seq<'T1 * 'T2> = + let ysCache = cache ys + delay (fun () -> + let mapping x = ysCache |> map (fun y -> (x, y)) + concat (map mapping xs) + ) + let mapFold (mapping: 'State -> 'T -> 'Result * 'State) state (xs: seq<'T>) = let arr, state = Array.mapFold mapping state (toArray xs) readOnly arr, state @@ -747,10 +681,15 @@ let scanBack folder (xs: seq<'T>) (state: 'State) = let skip count (xs: seq<'T>) = mkSeq (fun () -> let e = ofSeq xs - for i = 1 to count do - if not (e.MoveNext()) then - invalidArg "source" SR.notEnoughElements - e + try + for i = 1 to count do + if not (e.MoveNext()) then + invalidArg "source" SR.notEnoughElements + let compensation () = () + Enumerator.enumerateThenFinally compensation e + with _ -> + e.Dispose() + reraise() ) let skipWhile predicate (xs: seq<'T>) = @@ -759,56 +698,47 @@ let skipWhile predicate (xs: seq<'T>) = xs |> filter (fun x -> if skipped then skipped <- predicate x - not skipped) + not skipped + ) ) let tail (xs: seq<'T>) = skip 1 xs let take count (xs: seq<'T>) = - mkSeq (fun () -> - let mutable i = 0 - ofSeq xs - |> Enumerator.unfold (fun e -> - i <- i + 1 - if i <= count then + generateIndexed + (fun () -> ofSeq xs) + (fun i e -> + if i < count then if e.MoveNext() - then Some (e.Current, e) + then Some (e.Current) else invalidArg "source" SR.notEnoughElements else None) - ) + (fun e -> e.Dispose()) let takeWhile predicate (xs: seq<'T>) = - mkSeq (fun () -> - ofSeq xs - |> Enumerator.unfold (fun e -> + generate + (fun () -> ofSeq xs) + (fun e -> if e.MoveNext() && predicate e.Current - then Some (e.Current, e) + then Some (e.Current) else None) - ) + (fun e -> e.Dispose()) let truncate count (xs: seq<'T>) = - mkSeq (fun () -> - let mutable i = 0 - ofSeq xs - |> Enumerator.unfold (fun e -> - i <- i + 1 - if i <= count && e.MoveNext() - then Some (e.Current, e) + generateIndexed + (fun () -> ofSeq xs) + (fun i e -> + if i < count && e.MoveNext() + then Some (e.Current) else None) - ) + (fun e -> e.Dispose()) let zip (xs: seq<'T1>) (ys: seq<'T2>) = - mkSeq (fun () -> - (ofSeq xs, ofSeq ys) - ||> Enumerator.map2 (fun x y -> (x, y)) - ) + map2 (fun x y -> (x, y)) xs ys let zip3 (xs: seq<'T1>) (ys: seq<'T2>) (zs: seq<'T3>) = - mkSeq (fun () -> - (ofSeq xs, ofSeq ys, ofSeq zs) - |||> Enumerator.map3 (fun x y z -> (x, y, z)) - ) + map3 (fun x y z -> (x, y, z)) xs ys zs let collect (mapping: 'T -> 'U seq) (xs: seq<'T>) = delay (fun () -> @@ -817,22 +747,6 @@ let collect (mapping: 'T -> 'U seq) (xs: seq<'T>) = |> concat ) -let groupBy (projection: 'T -> 'Key) (xs: seq<'T>) = - delay (fun () -> - xs - |> toArray - |> Array.groupBy projection - |> ofArray - ) - -let countBy (projection: 'T -> 'Key) (xs: seq<'T>) = - delay (fun () -> - xs - |> toArray - |> Array.countBy projection - |> ofArray - ) - let where predicate (xs: seq<'T>) = filter predicate xs @@ -872,22 +786,10 @@ let transpose (xss: seq<#seq<'T>>) = |> ofArray ) -let distinct (xs: seq<'T>) = - delay (fun () -> - let hashSet = System.Collections.Generic.HashSet(HashIdentity.Structural) - xs |> choose (fun x -> if hashSet.Add(x) then Some x else None) - ) - -let distinctBy (projection: 'T -> 'Key) (xs: seq<'T>) = - delay (fun () -> - let hashSet = System.Collections.Generic.HashSet(HashIdentity.Structural) - xs |> choose (fun x -> if hashSet.Add(projection x) then Some x else None) - ) - let sortWith (comparer: 'T -> 'T -> int) (xs: seq<'T>) = delay (fun () -> let arr = toArray xs - Array.sortInPlaceWith comparer arr // TODO: use stable sort (in JS it already is) + Array.sortInPlaceWith comparer arr // Note: In JS this sort is stable arr |> ofArray ) @@ -950,24 +852,6 @@ let chunkBySize (chunkSize: int) (xs: seq<'T>): seq> = |> ofArray ) -let cache (xs: seq<'T>) = - let mutable cached = false - let xsCache = ResizeArray() - delay (fun () -> - if not cached then - cached <- true - xs |> map (fun x -> xsCache.Add(x); x) - else - xsCache :> seq<'T> - ) - -let allPairs (xs: seq<'T1>) (ys: seq<'T2>): seq<'T1 * 'T2> = - let ysCache = cache ys - delay (fun () -> - let mapping x = ysCache |> map (fun y -> (x, y)) - concat (map mapping xs) - ) - // let init = initialize // let initInfinite = initializeInfinite // let iter = iterate diff --git a/src/fable-library/Seq2.fs b/src/fable-library/Seq2.fs new file mode 100644 index 0000000000..d86ceffcab --- /dev/null +++ b/src/fable-library/Seq2.fs @@ -0,0 +1,90 @@ +// split from Seq to remove circular dependencies +module SeqModule2 + +open Fable.Core + +let distinct (xs: seq<'T>) ([] comparer: System.Collections.Generic.IEqualityComparer<'T>) = + Seq.delay (fun () -> + let hashSet = System.Collections.Generic.HashSet<'T>(comparer) + xs |> Seq.filter (fun x -> hashSet.Add(x)) + ) + +let distinctBy (projection: 'T -> 'Key) (xs: seq<'T>) ([] comparer: System.Collections.Generic.IEqualityComparer<'Key>) = + Seq.delay (fun () -> + let hashSet = System.Collections.Generic.HashSet<'Key>(comparer) + xs |> Seq.filter (fun x -> hashSet.Add(projection x)) + ) + +let except (itemsToExclude: seq<'T>) (xs: seq<'T>) ([] comparer: System.Collections.Generic.IEqualityComparer<'T>) = + Seq.delay (fun () -> + let hashSet = System.Collections.Generic.HashSet<'T>(itemsToExclude, comparer) + xs |> Seq.filter (fun x -> hashSet.Add(x)) + ) + +let countBy (projection: 'T -> 'Key) (xs: seq<'T>) ([] comparer: System.Collections.Generic.IEqualityComparer<'Key>): ('Key * int) seq = + Seq.delay (fun () -> + let dict = System.Collections.Generic.Dictionary<'Key, int>(comparer) + let keys = ResizeArray<'Key>() + for x in xs do + let key = projection x + match dict.TryGetValue(key) with + | true, prev -> + dict.[key] <- prev + 1 + | false, _ -> + dict.[key] <- 1 + keys.Add(key) + Seq.map (fun key -> key, dict.[key]) keys + ) + +let groupBy (projection: 'T -> 'Key) (xs: seq<'T>) ([] comparer: System.Collections.Generic.IEqualityComparer<'Key>): ('Key * seq<'T>) seq = + Seq.delay (fun () -> + let dict = System.Collections.Generic.Dictionary<'Key, ResizeArray<'T>>(comparer) + let keys = ResizeArray<'Key>() + for x in xs do + let key = projection x + match dict.TryGetValue(key) with + | true, prev -> + prev.Add(x) + | false, _ -> + dict.Add(key, ResizeArray [|x|]) + keys.Add(key) + Seq.map (fun key -> key, dict.[key] :> seq<'T>) keys + ) + +module Array = + + let distinct (xs: 'T[]) ([] comparer: System.Collections.Generic.IEqualityComparer<'T>): 'T[] = + distinct xs comparer |> Seq.toArray + + let distinctBy (projection: 'T -> 'Key) (xs: 'T[]) ([] comparer: System.Collections.Generic.IEqualityComparer<'Key>): 'T[] = + distinctBy projection xs comparer |> Seq.toArray + + let except (itemsToExclude: seq<'T>) (xs: 'T[]) ([] comparer: System.Collections.Generic.IEqualityComparer<'T>): 'T[] = + except itemsToExclude xs comparer |> Seq.toArray + + let countBy (projection: 'T -> 'Key) (xs: 'T[]) ([] comparer: System.Collections.Generic.IEqualityComparer<'Key>): ('Key * int)[] = + countBy projection xs comparer |> Seq.toArray + + let groupBy (projection: 'T -> 'Key) (xs: 'T[]) ([] comparer: System.Collections.Generic.IEqualityComparer<'Key>): ('Key * 'T[])[] = + groupBy projection xs comparer + |> Seq.map (fun (key, values) -> key, Seq.toArray values) + |> Seq.toArray + +module List = + + let distinct (xs: 'T list) ([] comparer: System.Collections.Generic.IEqualityComparer<'T>): 'T list = + distinct xs comparer |> Seq.toList + + let distinctBy (projection: 'T -> 'Key) (xs: 'T list) ([] comparer: System.Collections.Generic.IEqualityComparer<'Key>): 'T list = + distinctBy projection xs comparer |> Seq.toList + + let except (itemsToExclude: seq<'T>) (xs: 'T list) ([] comparer: System.Collections.Generic.IEqualityComparer<'T>): 'T list = + except itemsToExclude xs comparer |> Seq.toList + + let countBy (projection: 'T -> 'Key) (xs: 'T list) ([] comparer: System.Collections.Generic.IEqualityComparer<'Key>): ('Key * int) list = + countBy projection xs comparer |> Seq.toList + + let groupBy (projection: 'T -> 'Key) (xs: 'T list) ([] comparer: System.Collections.Generic.IEqualityComparer<'Key>): ('Key * 'T list) list = + groupBy projection xs comparer + |> Seq.map (fun (key, values) -> key, Seq.toList values) + |> Seq.toList diff --git a/src/fable-library/Set.fs b/src/fable-library/Set.fs index 4920f9b688..407e4ec392 100644 --- a/src/fable-library/Set.fs +++ b/src/fable-library/Set.fs @@ -588,6 +588,8 @@ module SetTree = use ie = c.GetEnumerator() mkFromEnumerator comparer empty ie +open Fable.Core + [] [] [] @@ -689,7 +691,7 @@ type Set<[]'T when 'T: comparison >(comparer:IComparer<'T else Set(s.Comparer, SetTree.filter s.Comparer f s.Tree) - member s.Map(f, [] comparer: IComparer<'U>) : Set<'U> = + member s.Map(f, [] comparer: IComparer<'U>) : Set<'U> = Set(comparer, SetTree.fold (fun acc k -> SetTree.add comparer (f k) acc) (SetTree.empty) s.Tree) member s.Exists f = @@ -835,7 +837,7 @@ let contains element (set: Set<'T>) = set.Contains element let add value (set: Set<'T>) = set.Add value // [] -let singleton (value: 'T) ([] comparer: IComparer<'T>) : Set<'T> = +let singleton (value: 'T) ([] comparer: IComparer<'T>) : Set<'T> = Set<'T>.Empty(comparer).Add value // [] @@ -845,7 +847,7 @@ let remove value (set: Set<'T>) = set.Remove value let union (set1: Set<'T>) (set2: Set<'T>) = set1 + set2 // [] -let unionMany (sets: seq>) ([] comparer: IComparer<'T>) = +let unionMany (sets: seq>) ([] comparer: IComparer<'T>) = Seq.fold (fun s1 s2 -> s1 + s2) (Set<'T>.Empty comparer) sets // [] @@ -858,7 +860,7 @@ let intersectMany (sets: seq>) = Set.IntersectionMany sets let iterate action (set: Set<'T>) = set.Iterate action // [] -let empty<'T when 'T : comparison> ([] comparer: IComparer<'T>): Set<'T> = Set<'T>.Empty comparer +let empty<'T when 'T : comparison> ([] comparer: IComparer<'T>): Set<'T> = Set<'T>.Empty comparer // [] let forAll predicate (set: Set<'T>) = set.ForAll predicate @@ -879,17 +881,17 @@ let fold<'T, 'State when 'T : comparison> folder (state:'State) (set: Set<'T>) let foldBack<'T, 'State when 'T : comparison> folder (set: Set<'T>) (state:'State) = SetTree.foldBack folder set.Tree state // [] -let map mapping (set: Set<'T>) ([] comparer: IComparer<'U>) = set.Map(mapping, comparer) +let map mapping (set: Set<'T>) ([] comparer: IComparer<'U>) = set.Map(mapping, comparer) // [] let count (set: Set<'T>) = set.Count // [] -let ofList elements ([] comparer: IComparer<'T>) = +let ofList elements ([] comparer: IComparer<'T>) = Set(comparer, SetTree.ofSeq comparer elements) // [] -let ofArray (array: 'T array) ([] comparer: IComparer<'T>) = +let ofArray (array: 'T array) ([] comparer: IComparer<'T>) = Set(comparer, SetTree.ofArray comparer array) // [] @@ -902,7 +904,7 @@ let toArray (set: Set<'T>) = set.ToArray() let toSeq (set: Set<'T>) = (set |> Seq.map id) // [] -let ofSeq (elements: seq<_>) ([] comparer: IComparer<'T>) = +let ofSeq (elements: seq<_>) ([] comparer: IComparer<'T>) = Set(comparer, SetTree.ofSeq comparer elements) // [] @@ -926,32 +928,12 @@ let minElement (set: Set<'T>) = set.MinimumElement // [] let maxElement (set: Set<'T>) = set.MaximumElement -let createMutable (source: seq<'T>) ([] comparer: IEqualityComparer<'T>) = - let set = Fable.Collections.MutableSet(source, comparer) - set :> Fable.Core.JS.Set<_> - -let distinct (xs: seq<'T>) ([] comparer: IEqualityComparer<'T>) = - seq { - let set = Fable.Collections.MutableSet(Seq.empty, comparer) - for x in xs do - if set.Add(x) then - yield x - } - -let distinctBy (projection: 'T -> 'Key) (xs: seq<'T>) ([] comparer: IEqualityComparer<'Key>) = - seq { - let set = Fable.Collections.MutableSet(Seq.empty, comparer) - for x in xs do - if set.Add(projection x) then - yield x - } - // Helpers to replicate HashSet methods let unionWith (s1: Fable.Core.JS.Set<'T>) (s2: 'T seq) = (s1, s2) ||> Seq.fold (fun acc x -> acc.add x) -let intersectWith (s1: Fable.Core.JS.Set<'T>) (s2: 'T seq) ([] comparer: IComparer<'T>) = +let intersectWith (s1: Fable.Core.JS.Set<'T>) (s2: 'T seq) ([] comparer: IComparer<'T>) = let s2 = ofSeq s2 comparer for x in s1.keys() do if not (s2.Contains x) then @@ -961,14 +943,14 @@ let exceptWith (s1: Fable.Core.JS.Set<'T>) (s2: 'T seq) = for x in s2 do s1.delete x |> ignore -let isSubsetOf (s1: Fable.Core.JS.Set<'T>) (s2: 'T seq) ([] comparer: IComparer<'T>) = +let isSubsetOf (s1: Fable.Core.JS.Set<'T>) (s2: 'T seq) ([] comparer: IComparer<'T>) = isSubset (ofSeq (s1.values()) comparer) (ofSeq s2 comparer) -let isSupersetOf (s1: Fable.Core.JS.Set<'T>) (s2: 'T seq) ([] comparer: IComparer<'T>) = +let isSupersetOf (s1: Fable.Core.JS.Set<'T>) (s2: 'T seq) ([] comparer: IComparer<'T>) = isSuperset (ofSeq (s1.values()) comparer) (ofSeq s2 comparer) -let isProperSubsetOf (s1: Fable.Core.JS.Set<'T>) (s2: 'T seq) ([] comparer: IComparer<'T>) = +let isProperSubsetOf (s1: Fable.Core.JS.Set<'T>) (s2: 'T seq) ([] comparer: IComparer<'T>) = isProperSubset (ofSeq (s1.values()) comparer) (ofSeq s2 comparer) -let isProperSupersetOf (s1: Fable.Core.JS.Set<'T>) (s2: 'T seq) ([] comparer: IComparer<'T>) = +let isProperSupersetOf (s1: Fable.Core.JS.Set<'T>) (s2: 'T seq) ([] comparer: IComparer<'T>) = isProperSuperset (ofSeq (s1.values()) comparer) (ofSeq s2 comparer) diff --git a/src/fable-library/System.Text.fs b/src/fable-library/System.Text.fs index c22e9d58ee..2b889e69c8 100644 --- a/src/fable-library/System.Text.fs +++ b/src/fable-library/System.Text.fs @@ -18,7 +18,11 @@ type StringBuilder(value: string, capacity: int) = member x.AppendLine() = buf.Add(System.Environment.NewLine); x member x.AppendLine(s: string) = buf.Add(s); buf.Add(System.Environment.NewLine); x override __.ToString() = System.String.Concat(buf) - member x.Length = buf |> Seq.sumBy String.length + member x.Length = + let mutable len = 0 + for i = buf.Count - 1 downto 0 do + len <- len + buf.Item(i).Length + len member x.ToString(firstIndex: int, length: int) = let str = x.ToString() str.Substring(firstIndex, length) diff --git a/src/tools/InjectProcessor/InjectProcessor.fs b/src/tools/InjectProcessor/InjectProcessor.fs index 1840775129..bb4267d9ac 100644 --- a/src/tools/InjectProcessor/InjectProcessor.fs +++ b/src/tools/InjectProcessor/InjectProcessor.fs @@ -89,17 +89,7 @@ let main _argv = module Fable.Transforms.ReplacementsInject let fableReplacementsModules = - Map [ - "Seq", Map [ - "maxBy", (Types.comparer, 1) - "max", (Types.comparer, 0) - "minBy", (Types.comparer, 1) - "min", (Types.comparer, 0) - "sumBy", (Types.adder, 1) - "sum", (Types.adder, 0) - "averageBy", (Types.averager, 1) - "average", (Types.averager, 0) - ]""" + Map [""" for file in proj.AssemblyContents.ImplementationFiles do let fileName = System.IO.Path.GetFileNameWithoutExtension(file.FileName) // Apparently FCS generates the AssemblyInfo file automatically