From 9e06b150a543726cbf86ae248c42498aad922856 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Wed, 28 Sep 2016 11:42:15 +0200 Subject: [PATCH 01/59] Basis of SeqComposer - Removed all dynamic casting - Split enumerable/enumerator - Implementations of map, filter, skip, pairwise Fixed output due to change in Seq.map delayed component creation to respect mutability - Added take, mapi - Added same exceptions for skip & take - Added composable skip & take - Added array source - Added source specific folding for functions like sum (required growing of surface area, so currently not exposed) Temporarily remove the ISeqEnumerable interface It was causing build issues as it was currently unused. Fixing halting on take Return current as match of match statement for perf *slight* performance improvement --- src/fsharp/FSharp.Core/seq.fs | 472 +++++++++++++++--- ...tailcalls.NoNeedToTailcall.output.test.bsl | 2 +- 2 files changed, 410 insertions(+), 64 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index ca062b62d2a..afff06239bb 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -15,7 +15,6 @@ namespace Microsoft.FSharp.Collections module IEnumerator = - let noReset() = raise (new System.NotSupportedException(SR.GetString(SR.resetNotSupported))) let notStarted() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationNotStarted))) let alreadyFinished() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationAlreadyFinished))) @@ -109,18 +108,6 @@ namespace Microsoft.FSharp.Collections interface System.IDisposable with member this.Dispose() = this.Dispose() - let map f (e : IEnumerator<_>) : IEnumerator<_>= - upcast - { new MapEnumerator<_>() with - member this.DoMoveNext (curr : byref<_>) = - if e.MoveNext() then - curr <- (f e.Current) - true - else - false - member this.Dispose() = e.Dispose() - } - let mapi f (e : IEnumerator<_>) : IEnumerator<_> = let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) let i = ref (-1) @@ -216,23 +203,6 @@ namespace Microsoft.FSharp.Collections interface System.IDisposable with member x.Dispose() = e.Dispose() } - let filter f (e : IEnumerator<'T>) = - let started = ref false - let this = - { new IEnumerator<'T> with - member x.Current = check !started; e.Current - interface IEnumerator with - member x.Current = check !started; box e.Current - member x.MoveNext() = - let rec next() = - if not !started then started := true - e.MoveNext() && (f e.Current || next()) - next() - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = e.Dispose() } - this - let unfold f x : IEnumerator<_> = let state = ref x upcast @@ -843,6 +813,395 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = +// type ISeqEnumerable<'T> = +// abstract member Fold<'State> : folder:('State->'T->'State) -> state:'State -> 'State + + module SeqComposer = + open IEnumerator + + module Helpers = + // used for performance reasons; these are not recursive calls, so should be safe + let inline avoidTailCall x = + match x with + | true -> true + | false -> false + + let inline ComposeFilter f g x = f x && g x + + type [] SeqComponent<'T,'U> () = + abstract ProcessNext : input:'T * halt:byref * output:byref<'U> -> bool + abstract OnComplete : unit -> unit + + abstract Composer : SeqComponent<'U,'V> -> SeqComponent<'T,'V> + + abstract ComposeMap<'S> : Map<'S,'T> -> SeqComponent<'S,'U> + abstract ComposeFilter : Filter<'T> -> SeqComponent<'T,'U> + abstract ComposeFilterMap<'S> : FilterMap<'S,'T> -> SeqComponent<'S,'U> + abstract ComposeMapFilter<'S> : MapFilter<'S,'T> -> SeqComponent<'S,'U> + abstract ComposeSkip : Skip<'T> -> SeqComponent<'T,'U> + + default __.OnComplete () = () + + default first.Composer (second:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Composed (first, second) + + default second.ComposeMap<'S> (first:Map<'S,'T>) : SeqComponent<'S,'U> = upcast Composed (first, second) + default second.ComposeFilter (first:Filter<'T>) : SeqComponent<'T,'U> = upcast Composed (first, second) + default second.ComposeFilterMap<'S> (first:FilterMap<'S,'T>) : SeqComponent<'S,'U> = upcast Composed (first, second) + default second.ComposeMapFilter<'S> (first:MapFilter<'S,'T>) : SeqComponent<'S,'U> = upcast Composed (first, second) + default second.ComposeSkip (first:Skip<'T>) : SeqComponent<'T,'U> = upcast Composed (first, second) + + and Composed<'T,'U,'V> (first:SeqComponent<'T,'U>, second:SeqComponent<'U,'V>) = + inherit SeqComponent<'T,'V>() + + override __.ProcessNext (input:'T, halted:byref, output:byref<'V>) :bool = + let mutable temp = Unchecked.defaultof<'U> + if first.ProcessNext (input, &halted, &temp) then + second.ProcessNext (temp, &halted, &output) + else + false + + override __.Composer (next:SeqComponent<'V,'W>) : SeqComponent<'T,'W> = + upcast Composed (first, second.Composer next) + + override __.OnComplete () = + first.OnComplete () + second.OnComplete () + + and Map<'T,'U> (map:'T->'U) = + inherit SeqComponent<'T,'U>() + + override first.Composer (second:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = + second.ComposeMap first + + override second.ComposeMap<'S> (first:Map<'S,'T>) : SeqComponent<'S,'U> = + upcast Map (first.Map >> second.Map) + + override second.ComposeFilter (first:Filter<'T>) : SeqComponent<'T,'U> = + upcast FilterMap (first.Filter, second.Map) + + override second.ComposeFilterMap<'S> (first:FilterMap<'S,'T>) : SeqComponent<'S,'U> = + upcast FilterMap (first.Filter, first.Map >> second.Map) + + override __.ProcessNext (input:'T, halted:byref, output:byref<'U>) : bool = + output <- map input + true + + member __.Map : 'T->'U = map + + and Mapi<'T,'U> (mapi:int->'T->'U) = + inherit SeqComponent<'T,'U>() + + let mutable idx = 0 + + override __.ProcessNext (input:'T, halted:byref, output:byref<'U>) : bool = + output <- mapi idx input + idx <- idx + 1 + true + + member __.Mapi : int->'T->'U = mapi + + and Filter<'T> (filter:'T->bool) = + inherit SeqComponent<'T,'T>() + + override this.Composer (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = + next.ComposeFilter this + + override second.ComposeMap<'S> (first:Map<'S,'T>) : SeqComponent<'S,'T> = + upcast MapFilter (first.Map, second.Filter) + + override second.ComposeFilter (first:Filter<'T>) : SeqComponent<'T,'T> = + upcast Filter (Helpers.ComposeFilter first.Filter second.Filter) + + override second.ComposeMapFilter<'S> (first:MapFilter<'S,'T>) : SeqComponent<'S,'T> = + upcast MapFilter (first.Map, Helpers.ComposeFilter first.Filter second.Filter) + + override __.ProcessNext (input:'T, halted:byref, output:byref<'T>) : bool = + if filter input then + output <- input + true + else + false + + member __.Filter :'T->bool = filter + + and MapFilter<'T,'U> (map:'T->'U, filter:'U->bool) = + inherit SeqComponent<'T,'U>() + + override __.ProcessNext (input:'T, halted:byref, output:byref<'U>) :bool = + output <- map input + Helpers.avoidTailCall (filter output) + + override first.Composer (second:SeqComponent<'U,'V>):SeqComponent<'T,'V> = + second.ComposeMapFilter first + + member __.Map : 'T->'U = map + member __.Filter : 'U->bool = filter + + and FilterMap<'T,'U> (filter:'T->bool, map:'T->'U) = + inherit SeqComponent<'T,'U>() + + override __.ProcessNext (input:'T, halted:byref, output:byref<'U>) : bool = + if filter input then + output <- map input + true + else + false + + override this.Composer (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = next.ComposeFilterMap this + + member __.Filter : 'T->bool = filter + member __.Map : 'T->'U = map + + and Pairwise<'T> () = + inherit SeqComponent<'T,'T*'T>() + + let mutable isFirst = true + let mutable lastValue = Unchecked.defaultof<'T> + + override __.ProcessNext (input:'T, halted:byref, output:byref<'T*'T>) : bool = + if isFirst then + lastValue <- input + isFirst <- false + false + else + output <- lastValue, input + lastValue <- input + true + + and Skip<'T> (skipCount:int) = + inherit SeqComponent<'T,'T>() + + let mutable count = 0 + + override first.Composer (second:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = + second.ComposeSkip first + + override second.ComposeSkip (first:Skip<'T>) : SeqComponent<'T,'T> = + if System.Int32.MaxValue - second.SkipCount > first.SkipCount then + upcast Skip (first.SkipCount + second.SkipCount) + else + upcast Composed (first, second) + + override __.ProcessNext (input:'T, halted:byref, output:byref<'T>) : bool = + if count < skipCount then + count <- count + 1 + false + else + output <- input + true + + override __.OnComplete () = + if count < skipCount then + let x = skipCount - count + invalidOpFmt "tried to skip {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + + member __.SkipCount = skipCount + + and Take<'T> (takeCount:int) = + inherit SeqComponent<'T,'T>() + + let mutable count = 0 + + override second.ComposeSkip (first:Skip<'T>) : SeqComponent<'T,'T> = + if System.Int32.MaxValue - second.TakeCount > first.SkipCount then + upcast SkipTake (first.SkipCount, first.SkipCount+second.TakeCount) + else + upcast Composed (first, second) + + override __.ProcessNext (input:'T, halted:byref, output:byref<'T>) : bool = + if count < takeCount then + count <- count + 1 + output <- input + halted <- count = takeCount + true + else + halted <- true + false + + override __.OnComplete () = + if count < takeCount then + let x = takeCount - count + invalidOpFmt "tried to take {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + + member __.TakeCount = takeCount + + and SkipTake<'T> (startIdx:int, endIdx:int) = + inherit SeqComponent<'T,'T>() + + let mutable count = 0 + + override __.ProcessNext (input:'T, halted:byref, output:byref<'T>) : bool = + if count < startIdx then + count <- count + 1 + false + elif count < endIdx then + count <- count + 1 + output <- input + halted <- count = endIdx + true + else + halted <- true + false + + override __.OnComplete () = + if count < startIdx then + let x = startIdx - count + invalidOpFmt "tried to skip {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + elif count < endIdx then + let x = endIdx - count + invalidOpFmt "tried to take {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + + type SeqProcessNextStates = + | NotStarted = 1 + | Finished = 2 + | InProcess = 3 + + type SeqEnumeratorEnumerator<'T,'U>(enumerator:IEnumerator<'T>, t2u:SeqComponent<'T,'U>) = + let mutable state = SeqProcessNextStates.NotStarted + let mutable current = Unchecked.defaultof<'U> + let mutable halted = false + + let mutable source = enumerator + + let rec moveNext () = + if (not halted) && source.MoveNext () then + if t2u.ProcessNext (source.Current, &halted, ¤t) then + true + else + moveNext () + else + state <- SeqProcessNextStates.Finished + t2u.OnComplete () + false + + interface IDisposable with + member x.Dispose():unit = + match source with + | null -> () + | _ -> source.Dispose (); source <- Unchecked.defaultof<_> + + interface IEnumerator with + member this.Current : obj = box (this:>IEnumerator<'U>).Current + member __.MoveNext () = + state <- SeqProcessNextStates.InProcess + moveNext () + member __.Reset () : unit = noReset () + + interface IEnumerator<'U> with + member x.Current = + match state with + | SeqProcessNextStates.NotStarted -> notStarted() + | SeqProcessNextStates.Finished -> alreadyFinished() + | _ -> current + + type SeqArrayEnumerator<'T,'U>(array:array<'T>, t2u:SeqComponent<'T,'U>) = + let mutable state = SeqProcessNextStates.NotStarted + let mutable current = Unchecked.defaultof<'U> + let mutable halted = false + + let mutable idx = 0 + + let rec moveNext () = + if (not halted) && idx < array.Length then + idx <- idx+1 + if t2u.ProcessNext (array.[idx-1], &halted, ¤t) then + true + else + moveNext () + else + state <- SeqProcessNextStates.Finished + t2u.OnComplete () + false + + interface IDisposable with + member x.Dispose() : unit = () + + interface IEnumerator with + member this.Current : obj = box (this:>IEnumerator<'U>).Current + member __.MoveNext () = + state <- SeqProcessNextStates.InProcess + moveNext () + member __.Reset () : unit = noReset () + + interface IEnumerator<'U> with + member x.Current = + match state with + | SeqProcessNextStates.NotStarted -> notStarted() + | SeqProcessNextStates.Finished -> alreadyFinished() + | _ -> current + + [] + type ComposableEnumerable<'T> () = + abstract member Compose<'U> : (unit -> SeqComponent<'T,'U>) -> IEnumerable<'U> + + type SeqEnumerable<'T,'U>(enumerable:IEnumerable<'T>, current:unit->SeqComponent<'T,'U>) = + inherit ComposableEnumerable<'U>() + + let getEnumerator () : IEnumerator<'U> = + upcast (new SeqEnumeratorEnumerator<'T,'U>(enumerable.GetEnumerator(), current ())) + + interface IEnumerable with + member this.GetEnumerator () : IEnumerator = upcast (getEnumerator ()) + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = getEnumerator () + + override __.Compose (next:unit->SeqComponent<'U,'V>) : IEnumerable<'V> = + upcast new SeqEnumerable<'T,'V>(enumerable, fun () -> (current ()).Composer (next ())) + +// interface ISeqEnumerable<'U> with +// member this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = +// let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder +// +// let enumerator = enumerable.GetEnumerator () +// let components = current () +// let mutable output = Unchecked.defaultof<'U> +// let mutable halt = false +// +// let mutable state = initialState +// while (not halt) && enumerator.MoveNext () do +// if components.ProcessNext (enumerator.Current, &halt, &output) then +// state <- folder'.Invoke (state, output) +// +// state + + type SeqArrayEnumerable<'T,'U>(array:array<'T>, current:unit->SeqComponent<'T,'U>) = + inherit ComposableEnumerable<'U>() + + let getEnumerator () : IEnumerator<'U> = + upcast (new SeqArrayEnumerator<'T,'U>(array, current ())) + + interface IEnumerable with + member this.GetEnumerator () : IEnumerator = upcast (getEnumerator ()) + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = getEnumerator () + + override __.Compose (next:unit->SeqComponent<'U,'V>) : IEnumerable<'V> = + upcast new SeqArrayEnumerable<'T,'V>(array, fun () -> (current ()).Composer (next ())) + +// interface ISeqEnumerable<'U> with +// member this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = +// let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder +// +// let mutable idx = 0 +// let components = current () +// let mutable current = Unchecked.defaultof<'U> +// let mutable halt = false +// +// let mutable state = initialState +// while (not halt) && idx < array.Length do +// if components.ProcessNext (array.[idx], &halt, ¤t) then +// state <- folder'.Invoke(state, current) +// idx <- idx + 1 +// +// state + + #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions @@ -963,23 +1322,30 @@ namespace Microsoft.FSharp.Collections let revamp3 f (ie1 : seq<_>) (source2 : seq<_>) (source3 : seq<_>) = mkSeq (fun () -> f (ie1.GetEnumerator()) (source2.GetEnumerator()) (source3.GetEnumerator())) - [] - let filter f source = + let private seqFactory createSeqComponent (source:seq<'T>) = checkNonNull "source" source - revamp (IEnumerator.filter f) source + match source with + | :? SeqComposer.ComposableEnumerable<'T> as s -> s.Compose createSeqComponent + | :? array<'T> as a -> upcast (new SeqComposer.SeqArrayEnumerable<_,_>(a, createSeqComponent)) + | _ -> upcast (new SeqComposer.SeqEnumerable<_,_>(source, createSeqComponent)) + + let private seqFactoryForImmutable seqComponent (source:seq<'T>) = + source |> seqFactory (fun () -> seqComponent) + + [] + let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = + source |> seqFactoryForImmutable (SeqComposer.Filter f) [] - let where f source = filter f source + let where f source = filter f source [] - let map f source = - checkNonNull "source" source - revamp (IEnumerator.map f) source + let map<'T,'U> (f:'T->'U) (source:seq<'T>) : seq<'U> = + source |> seqFactoryForImmutable (SeqComposer.Map f) [] let mapi f source = - checkNonNull "source" source - revamp (IEnumerator.mapi f) source + source |> seqFactory (fun () -> upcast SeqComposer.Mapi f) [] let mapi2 f source1 source2 = @@ -1063,16 +1429,10 @@ namespace Microsoft.FSharp.Collections [] let take count (source : seq<'T>) = - checkNonNull "source" source if count < 0 then invalidArgInputMustBeNonNegative "count" count (* Note: don't create or dispose any IEnumerable if n = 0 *) if count = 0 then empty else - seq { use e = source.GetEnumerator() - for x in 0 .. count - 1 do - if not (e.MoveNext()) then - invalidOpFmt "tried to take {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - yield e.Current } + source |> seqFactory (fun () -> upcast SeqComposer.Take count) [] let isEmpty (source : seq<'T>) = @@ -1252,15 +1612,8 @@ namespace Microsoft.FSharp.Collections yield ie.Current } [] - let pairwise (source: seq<'T>) = - checkNonNull "source" source - seq { use ie = source.GetEnumerator() - if ie.MoveNext() then - let iref = ref ie.Current - while ie.MoveNext() do - let j = ie.Current - yield (!iref, j) - iref := j } + let pairwise<'T> (source:seq<'T>) : seq<'T*'T> = + source |> seqFactory (fun () -> upcast SeqComposer.Pairwise ()) [] let scan<'T,'State> f (z:'State) (source : seq<'T>) = @@ -1698,14 +2051,7 @@ namespace Microsoft.FSharp.Collections [] let skip count (source: seq<_>) = - checkNonNull "source" source - seq { use e = source.GetEnumerator() - for x in 1 .. count do - if not (e.MoveNext()) then - invalidOpFmt "tried to skip {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - while e.MoveNext() do - yield e.Current } + source |> seqFactory (fun () -> upcast SeqComposer.Skip count) [] let skipWhile p (source: seq<_>) = diff --git a/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl b/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl index 5f4e677efc6..785a337a2f4 100644 --- a/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl +++ b/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl @@ -38,7 +38,7 @@ value simpleLibraryCall6 at line 60 does not make a critical tailcall value simpleLibraryCall7 at line 61 does not make a critical tailcall value simpleLibraryCall8 at line 62 does not make a critical tailcall value simpleLibraryCall9 at line 63 does not make a critical tailcall -value simpleLibraryCall10 at line 65 does not make a critical tailcall +value simpleLibraryCall10 at line 65 may make a critical tailcall value simpleLibraryCall11 at line 66 does not make a critical tailcall value simpleLibraryCall12 at line 67 does not make a critical tailcall value simpleLibraryCall13 at line 68 does not make a critical tailcall From 6e6129bc086b5afc22bd1a63cdcdb08a71f378f8 Mon Sep 17 00:00:00 2001 From: liboz Date: Mon, 3 Oct 2016 16:34:00 -0400 Subject: [PATCH 02/59] renaming cleanup. Adding ListEnumerable. Adding Choose --- src/fsharp/FSharp.Core/seq.fs | 149 ++++++++++++++++++++++++---------- 1 file changed, 104 insertions(+), 45 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index afff06239bb..58f034d1914 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -834,21 +834,21 @@ namespace Microsoft.FSharp.Collections abstract Composer : SeqComponent<'U,'V> -> SeqComponent<'T,'V> - abstract ComposeMap<'S> : Map<'S,'T> -> SeqComponent<'S,'U> - abstract ComposeFilter : Filter<'T> -> SeqComponent<'T,'U> - abstract ComposeFilterMap<'S> : FilterMap<'S,'T> -> SeqComponent<'S,'U> - abstract ComposeMapFilter<'S> : MapFilter<'S,'T> -> SeqComponent<'S,'U> - abstract ComposeSkip : Skip<'T> -> SeqComponent<'T,'U> + abstract ComposeWithMap<'S> : Map<'S,'T> -> SeqComponent<'S,'U> + abstract ComposeWithFilter : Filter<'T> -> SeqComponent<'T,'U> + abstract ComposeWithFilterThenMap<'S> : FilterThenMap<'S,'T> -> SeqComponent<'S,'U> + abstract ComposeWithMapThenFilter<'S> : MapThenFilter<'S,'T> -> SeqComponent<'S,'U> + abstract ComposeWithSkip : Skip<'T> -> SeqComponent<'T,'U> default __.OnComplete () = () - default first.Composer (second:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Composed (first, second) + default first.Composer (second:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Composed (first, second) - default second.ComposeMap<'S> (first:Map<'S,'T>) : SeqComponent<'S,'U> = upcast Composed (first, second) - default second.ComposeFilter (first:Filter<'T>) : SeqComponent<'T,'U> = upcast Composed (first, second) - default second.ComposeFilterMap<'S> (first:FilterMap<'S,'T>) : SeqComponent<'S,'U> = upcast Composed (first, second) - default second.ComposeMapFilter<'S> (first:MapFilter<'S,'T>) : SeqComponent<'S,'U> = upcast Composed (first, second) - default second.ComposeSkip (first:Skip<'T>) : SeqComponent<'T,'U> = upcast Composed (first, second) + default second.ComposeWithMap<'S> (first:Map<'S,'T>) : SeqComponent<'S,'U> = upcast Composed (first, second) + default second.ComposeWithFilter (first:Filter<'T>) : SeqComponent<'T,'U> = upcast Composed (first, second) + default second.ComposeWithFilterThenMap<'S> (first:FilterThenMap<'S,'T>) : SeqComponent<'S,'U> = upcast Composed (first, second) + default second.ComposeWithMapThenFilter<'S> (first:MapThenFilter<'S,'T>) : SeqComponent<'S,'U> = upcast Composed (first, second) + default second.ComposeWithSkip (first:Skip<'T>) : SeqComponent<'T,'U> = upcast Composed (first, second) and Composed<'T,'U,'V> (first:SeqComponent<'T,'U>, second:SeqComponent<'U,'V>) = inherit SeqComponent<'T,'V>() @@ -871,16 +871,16 @@ namespace Microsoft.FSharp.Collections inherit SeqComponent<'T,'U>() override first.Composer (second:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = - second.ComposeMap first + second.ComposeWithMap first - override second.ComposeMap<'S> (first:Map<'S,'T>) : SeqComponent<'S,'U> = + override second.ComposeWithMap<'S> (first:Map<'S,'T>) : SeqComponent<'S,'U> = upcast Map (first.Map >> second.Map) - override second.ComposeFilter (first:Filter<'T>) : SeqComponent<'T,'U> = - upcast FilterMap (first.Filter, second.Map) + override second.ComposeWithFilter (first:Filter<'T>) : SeqComponent<'T,'U> = + upcast FilterThenMap (first.Filter, second.Map) - override second.ComposeFilterMap<'S> (first:FilterMap<'S,'T>) : SeqComponent<'S,'U> = - upcast FilterMap (first.Filter, first.Map >> second.Map) + override second.ComposeWithFilterThenMap<'S> (first:FilterThenMap<'S,'T>) : SeqComponent<'S,'U> = + upcast FilterThenMap (first.Filter, first.Map >> second.Map) override __.ProcessNext (input:'T, halted:byref, output:byref<'U>) : bool = output <- map input @@ -903,17 +903,17 @@ namespace Microsoft.FSharp.Collections and Filter<'T> (filter:'T->bool) = inherit SeqComponent<'T,'T>() - override this.Composer (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = - next.ComposeFilter this + override first.Composer (second:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = + second.ComposeWithFilter first - override second.ComposeMap<'S> (first:Map<'S,'T>) : SeqComponent<'S,'T> = - upcast MapFilter (first.Map, second.Filter) + override second.ComposeWithMap<'S> (first:Map<'S,'T>) : SeqComponent<'S,'T> = + upcast MapThenFilter (first.Map, second.Filter) - override second.ComposeFilter (first:Filter<'T>) : SeqComponent<'T,'T> = + override second.ComposeWithFilter (first:Filter<'T>) : SeqComponent<'T,'T> = upcast Filter (Helpers.ComposeFilter first.Filter second.Filter) - override second.ComposeMapFilter<'S> (first:MapFilter<'S,'T>) : SeqComponent<'S,'T> = - upcast MapFilter (first.Map, Helpers.ComposeFilter first.Filter second.Filter) + override second.ComposeWithMapThenFilter<'S> (first:MapThenFilter<'S,'T>) : SeqComponent<'S,'T> = + upcast MapThenFilter (first.Map, Helpers.ComposeFilter first.Filter second.Filter) override __.ProcessNext (input:'T, halted:byref, output:byref<'T>) : bool = if filter input then @@ -924,7 +924,7 @@ namespace Microsoft.FSharp.Collections member __.Filter :'T->bool = filter - and MapFilter<'T,'U> (map:'T->'U, filter:'U->bool) = + and MapThenFilter<'T,'U> (map:'T->'U, filter:'U->bool) = inherit SeqComponent<'T,'U>() override __.ProcessNext (input:'T, halted:byref, output:byref<'U>) :bool = @@ -932,12 +932,12 @@ namespace Microsoft.FSharp.Collections Helpers.avoidTailCall (filter output) override first.Composer (second:SeqComponent<'U,'V>):SeqComponent<'T,'V> = - second.ComposeMapFilter first + second.ComposeWithMapThenFilter first member __.Map : 'T->'U = map member __.Filter : 'U->bool = filter - and FilterMap<'T,'U> (filter:'T->bool, map:'T->'U) = + and FilterThenMap<'T,'U> (filter:'T->bool, map:'T->'U) = inherit SeqComponent<'T,'U>() override __.ProcessNext (input:'T, halted:byref, output:byref<'U>) : bool = @@ -947,7 +947,7 @@ namespace Microsoft.FSharp.Collections else false - override this.Composer (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = next.ComposeFilterMap this + override first.Composer (second:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = second.ComposeWithFilterThenMap first member __.Filter : 'T->bool = filter member __.Map : 'T->'U = map @@ -974,10 +974,10 @@ namespace Microsoft.FSharp.Collections let mutable count = 0 override first.Composer (second:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = - second.ComposeSkip first + second.ComposeWithSkip first - override second.ComposeSkip (first:Skip<'T>) : SeqComponent<'T,'T> = - if System.Int32.MaxValue - second.SkipCount > first.SkipCount then + override second.ComposeWithSkip (first:Skip<'T>) : SeqComponent<'T,'T> = + if Int32.MaxValue - first.SkipCount - second.SkipCount > 0 then upcast Skip (first.SkipCount + second.SkipCount) else upcast Composed (first, second) @@ -1003,9 +1003,9 @@ namespace Microsoft.FSharp.Collections let mutable count = 0 - override second.ComposeSkip (first:Skip<'T>) : SeqComponent<'T,'T> = - if System.Int32.MaxValue - second.TakeCount > first.SkipCount then - upcast SkipTake (first.SkipCount, first.SkipCount+second.TakeCount) + override second.ComposeWithSkip (first:Skip<'T>) : SeqComponent<'T,'T> = + if Int32.MaxValue - first.SkipCount - second.TakeCount > 0 then + upcast SkipThenTake (first.SkipCount, first.SkipCount+second.TakeCount) else upcast Composed (first, second) @@ -1027,7 +1027,7 @@ namespace Microsoft.FSharp.Collections member __.TakeCount = takeCount - and SkipTake<'T> (startIdx:int, endIdx:int) = + and SkipThenTake<'T> (startIdx:int, endIdx:int) = inherit SeqComponent<'T,'T>() let mutable count = 0 @@ -1054,13 +1054,22 @@ namespace Microsoft.FSharp.Collections let x = endIdx - count invalidOpFmt "tried to take {0} {1} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + + and Choose<'T, 'U> (choose:'T->'U option) = + inherit SeqComponent<'T,'U>() + + override __.ProcessNext (input:'T, halted:byref, output:byref<'U>) : bool = + match choose input with + | Some value -> output <- value + true + | None -> false type SeqProcessNextStates = | NotStarted = 1 | Finished = 2 | InProcess = 3 - type SeqEnumeratorEnumerator<'T,'U>(enumerator:IEnumerator<'T>, t2u:SeqComponent<'T,'U>) = + type SeqComposedEnumerator<'T,'U>(enumerator:IEnumerator<'T>, t2u:SeqComponent<'T,'U>) = let mutable state = SeqProcessNextStates.NotStarted let mutable current = Unchecked.defaultof<'U> let mutable halted = false @@ -1079,7 +1088,7 @@ namespace Microsoft.FSharp.Collections false interface IDisposable with - member x.Dispose():unit = + member __.Dispose():unit = match source with | null -> () | _ -> source.Dispose (); source <- Unchecked.defaultof<_> @@ -1092,13 +1101,13 @@ namespace Microsoft.FSharp.Collections member __.Reset () : unit = noReset () interface IEnumerator<'U> with - member x.Current = + member __.Current = match state with | SeqProcessNextStates.NotStarted -> notStarted() | SeqProcessNextStates.Finished -> alreadyFinished() | _ -> current - type SeqArrayEnumerator<'T,'U>(array:array<'T>, t2u:SeqComponent<'T,'U>) = + type ArrayComposedEnumerator<'T,'U>(array:array<'T>, t2u:SeqComponent<'T,'U>) = let mutable state = SeqProcessNextStates.NotStarted let mutable current = Unchecked.defaultof<'U> let mutable halted = false @@ -1118,7 +1127,7 @@ namespace Microsoft.FSharp.Collections false interface IDisposable with - member x.Dispose() : unit = () + member __.Dispose() : unit = () interface IEnumerator with member this.Current : obj = box (this:>IEnumerator<'U>).Current @@ -1128,7 +1137,43 @@ namespace Microsoft.FSharp.Collections member __.Reset () : unit = noReset () interface IEnumerator<'U> with - member x.Current = + member __.Current = + match state with + | SeqProcessNextStates.NotStarted -> notStarted() + | SeqProcessNextStates.Finished -> alreadyFinished() + | _ -> current + + type ListComposedEnumerator<'T,'U>(alist:list<'T>, t2u:SeqComponent<'T,'U>) = + let mutable state = SeqProcessNextStates.NotStarted + let mutable current = Unchecked.defaultof<'U> + let mutable halted = false + + let mutable list = alist + + let rec moveNext () = + match halted, list with + | false, head::tail -> + list <- tail + if t2u.ProcessNext (head, &halted, ¤t) then + true + else + moveNext () + | _ -> state <- SeqProcessNextStates.Finished + t2u.OnComplete () + false + + interface IDisposable with + member __.Dispose() : unit = () + + interface IEnumerator with + member this.Current : obj = box (this:>IEnumerator<'U>).Current + member __.MoveNext () = + state <- SeqProcessNextStates.InProcess + moveNext () + member __.Reset () : unit = noReset () + + interface IEnumerator<'U> with + member __.Current = match state with | SeqProcessNextStates.NotStarted -> notStarted() | SeqProcessNextStates.Finished -> alreadyFinished() @@ -1142,7 +1187,7 @@ namespace Microsoft.FSharp.Collections inherit ComposableEnumerable<'U>() let getEnumerator () : IEnumerator<'U> = - upcast (new SeqEnumeratorEnumerator<'T,'U>(enumerable.GetEnumerator(), current ())) + upcast (new SeqComposedEnumerator<'T,'U>(enumerable.GetEnumerator(), current ())) interface IEnumerable with member this.GetEnumerator () : IEnumerator = upcast (getEnumerator ()) @@ -1173,7 +1218,7 @@ namespace Microsoft.FSharp.Collections inherit ComposableEnumerable<'U>() let getEnumerator () : IEnumerator<'U> = - upcast (new SeqArrayEnumerator<'T,'U>(array, current ())) + upcast (new ArrayComposedEnumerator<'T,'U>(array, current ())) interface IEnumerable with member this.GetEnumerator () : IEnumerator = upcast (getEnumerator ()) @@ -1201,6 +1246,20 @@ namespace Microsoft.FSharp.Collections // // state + type SeqListEnumerable<'T,'U>(alist:list<'T>, current:unit->SeqComponent<'T,'U>) = + inherit ComposableEnumerable<'U>() + + let getEnumerator () : IEnumerator<'U> = + upcast (new ListComposedEnumerator<'T,'U>(alist, current ())) + + interface IEnumerable with + member this.GetEnumerator () : IEnumerator = upcast (getEnumerator ()) + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = getEnumerator () + + override __.Compose (next:unit->SeqComponent<'U,'V>) : IEnumerable<'V> = + upcast new SeqListEnumerable<'T,'V>(alist, fun () -> (current ()).Composer (next ())) #if FX_NO_ICLONEABLE @@ -1327,6 +1386,7 @@ namespace Microsoft.FSharp.Collections match source with | :? SeqComposer.ComposableEnumerable<'T> as s -> s.Compose createSeqComponent | :? array<'T> as a -> upcast (new SeqComposer.SeqArrayEnumerable<_,_>(a, createSeqComponent)) + | :? list<'T> as a -> upcast (new SeqComposer.SeqListEnumerable<_,_>(a, createSeqComponent)) | _ -> upcast (new SeqComposer.SeqEnumerable<_,_>(source, createSeqComponent)) let private seqFactoryForImmutable seqComponent (source:seq<'T>) = @@ -1368,8 +1428,7 @@ namespace Microsoft.FSharp.Collections [] let choose f source = - checkNonNull "source" source - revamp (IEnumerator.choose f) source + source |> seqFactoryForImmutable (SeqComposer.Choose f) [] let indexed source = From d158bbbd2d52212fac552522017aaea12c1eccc6 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Tue, 4 Oct 2016 20:00:31 +1100 Subject: [PATCH 03/59] Remove unbox.any when upcasting to IEnumer(able|ator) Thanks to @liboz for reminding me of the performance hit here. This is noticeable when you have small collections to be iterated. --- src/fsharp/FSharp.Core/seq.fs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 58f034d1914..6895051cda0 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -828,6 +828,10 @@ namespace Microsoft.FSharp.Collections let inline ComposeFilter f g x = f x && g x + let inline UpcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) + let inline UpcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) + let inline UpcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) + type [] SeqComponent<'T,'U> () = abstract ProcessNext : input:'T * halt:byref * output:byref<'U> -> bool abstract OnComplete : unit -> unit @@ -1094,7 +1098,7 @@ namespace Microsoft.FSharp.Collections | _ -> source.Dispose (); source <- Unchecked.defaultof<_> interface IEnumerator with - member this.Current : obj = box (this:>IEnumerator<'U>).Current + member this.Current : obj = box (Helpers.UpcastEnumerator this).Current member __.MoveNext () = state <- SeqProcessNextStates.InProcess moveNext () @@ -1130,7 +1134,7 @@ namespace Microsoft.FSharp.Collections member __.Dispose() : unit = () interface IEnumerator with - member this.Current : obj = box (this:>IEnumerator<'U>).Current + member this.Current : obj = box ((Helpers.UpcastEnumerator this)).Current member __.MoveNext () = state <- SeqProcessNextStates.InProcess moveNext () @@ -1187,16 +1191,16 @@ namespace Microsoft.FSharp.Collections inherit ComposableEnumerable<'U>() let getEnumerator () : IEnumerator<'U> = - upcast (new SeqComposedEnumerator<'T,'U>(enumerable.GetEnumerator(), current ())) + Helpers.UpcastEnumerator (new SeqEnumeratorEnumerator<'T,'U>(enumerable.GetEnumerator(), current ())) interface IEnumerable with - member this.GetEnumerator () : IEnumerator = upcast (getEnumerator ()) + member this.GetEnumerator () : IEnumerator = Helpers.UpcastEnumeratorNonGeneric (getEnumerator ()) interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = getEnumerator () override __.Compose (next:unit->SeqComponent<'U,'V>) : IEnumerable<'V> = - upcast new SeqEnumerable<'T,'V>(enumerable, fun () -> (current ()).Composer (next ())) + Helpers.UpcastEnumerable (new SeqEnumerable<'T,'V>(enumerable, fun () -> (current ()).Composer (next ()))) // interface ISeqEnumerable<'U> with // member this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = @@ -1218,16 +1222,16 @@ namespace Microsoft.FSharp.Collections inherit ComposableEnumerable<'U>() let getEnumerator () : IEnumerator<'U> = - upcast (new ArrayComposedEnumerator<'T,'U>(array, current ())) + Helpers.UpcastEnumerator (new SeqArrayEnumerator<'T,'U>(array, current ())) interface IEnumerable with - member this.GetEnumerator () : IEnumerator = upcast (getEnumerator ()) + member this.GetEnumerator () : IEnumerator = Helpers.UpcastEnumeratorNonGeneric (getEnumerator ()) interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = getEnumerator () override __.Compose (next:unit->SeqComponent<'U,'V>) : IEnumerable<'V> = - upcast new SeqArrayEnumerable<'T,'V>(array, fun () -> (current ()).Composer (next ())) + Helpers.UpcastEnumerable (new SeqArrayEnumerable<'T,'V>(array, fun () -> (current ()).Composer (next ()))) // interface ISeqEnumerable<'U> with // member this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = @@ -1385,9 +1389,9 @@ namespace Microsoft.FSharp.Collections checkNonNull "source" source match source with | :? SeqComposer.ComposableEnumerable<'T> as s -> s.Compose createSeqComponent - | :? array<'T> as a -> upcast (new SeqComposer.SeqArrayEnumerable<_,_>(a, createSeqComponent)) - | :? list<'T> as a -> upcast (new SeqComposer.SeqListEnumerable<_,_>(a, createSeqComponent)) - | _ -> upcast (new SeqComposer.SeqEnumerable<_,_>(source, createSeqComponent)) + | :? array<'T> as a -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.SeqArrayEnumerable<_,_>(a, createSeqComponent)) + | :? list<'T> as a -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.SeqListEnumerable<_,_>(a, createSeqComponent)) + | _ -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.SeqEnumerable<_,_>(source, createSeqComponent)) let private seqFactoryForImmutable seqComponent (source:seq<'T>) = source |> seqFactory (fun () -> seqComponent) From babf7b4705dccede696d8679d262c58199f34d43 Mon Sep 17 00:00:00 2001 From: liboz Date: Wed, 5 Oct 2016 04:13:24 +0200 Subject: [PATCH 04/59] remove old mapi function skipwhile/takewhile --- src/fsharp/FSharp.Core/seq.fs | 61 ++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 6895051cda0..12533201ea2 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -108,21 +108,6 @@ namespace Microsoft.FSharp.Collections interface System.IDisposable with member this.Dispose() = this.Dispose() - let mapi f (e : IEnumerator<_>) : IEnumerator<_> = - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let i = ref (-1) - upcast - { new MapEnumerator<_>() with - member this.DoMoveNext curr = - i := !i + 1 - if e.MoveNext() then - curr <- f.Invoke(!i, e.Current) - true - else - false - member this.Dispose() = e.Dispose() - } - let map2 f (e1 : IEnumerator<_>) (e2 : IEnumerator<_>) : IEnumerator<_>= let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) upcast @@ -1058,7 +1043,35 @@ namespace Microsoft.FSharp.Collections let x = endIdx - count invalidOpFmt "tried to take {0} {1} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - + + and SkipWhile<'T> (predicate: 'T -> bool) = + inherit SeqComponent<'T,'T>() + + let mutable skip = true + + override __.ProcessNext (input:'T, halted:byref, output:byref<'T>) : bool = + if skip then + skip <- predicate input + if skip then + false + else + output <- input + true + else + output <- input + true + + and TakeWhile<'T> (predicate: 'T -> bool) = + inherit SeqComponent<'T,'T>() + + override __.ProcessNext (input:'T, halted:byref, output:byref<'T>) : bool = + if predicate input then + output <- input + true + else + halted <- true + false + and Choose<'T, 'U> (choose:'T->'U option) = inherit SeqComponent<'T,'U>() @@ -2106,11 +2119,7 @@ namespace Microsoft.FSharp.Collections *) [] let takeWhile p (source: seq<_>) = - checkNonNull "source" source - seq { use e = source.GetEnumerator() - let latest = ref Unchecked.defaultof<_> - while e.MoveNext() && (latest := e.Current; p !latest) do - yield !latest } + source |> seqFactory (fun () -> upcast SeqComposer.TakeWhile p) [] let skip count (source: seq<_>) = @@ -2118,15 +2127,7 @@ namespace Microsoft.FSharp.Collections [] let skipWhile p (source: seq<_>) = - checkNonNull "source" source - seq { use e = source.GetEnumerator() - let latest = ref (Unchecked.defaultof<_>) - let ok = ref false - while e.MoveNext() do - if (latest := e.Current; (!ok || not (p !latest))) then - ok := true - yield !latest } - + source |> seqFactory (fun () -> upcast SeqComposer.SkipWhile p) [] let forall2 p (source1: seq<_>) (source2: seq<_>) = From c312614df9c5b41d8e12a94ac92d9fdf3cd8b5e9 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Fri, 7 Oct 2016 11:18:45 +0200 Subject: [PATCH 05/59] Changes SeqComposer to build bottom-up A more direct calling process. Slows things down *slightly* when only a single item is being processed, but is a better model to build from going forward. Remove unused member Simplified ProcessNext call by creating Result object Due to the bottom-up build process I now have a consistent output signature, which allowed it to be wrapped in an single object rather than being passed up and down the chain of ProcessNext calls. default -> override OptimizedClosure for mapi Consolidated code in base class ensuring performance Retained MoveNext in derived class to ensure we didn't add an extra virtual call into the call stack. Added ComposableEnumerableFactoryHelper Sweeping up common functionality init(Infinite)? implementations Not as simple as it should be due to the original implementation deciding to evaluate Current in a lazy fashion. Comments have been splattered around hopefully describing the situation in enough detail. Split Result object in multi-leveled Signal The plan is to then implement fold like functionality in a Tail like object that we can expose out in a public interface, so I'm trying to minimize what would be needed to be visible externally. Rearranged Enumerator/Enumerable pairs together Fix bug in skipping an init seq Restoring to last successful build server build I probably don't have any more time today to bug issues init/initInfinite Try again, without any other clutter Bug fix; off by 1... Moved Enumerable/Enumerator pairs into modules map2 Fix OnComplete/OnDispose Hmmm... not 100% happy with this because it requires all links in the chain to ensure that that follow the protocol, but it isn't too bad I guess... Seq.append This implemention performs vastly better than the previous implementation, which appeared to be more interested in being theoretically important than actually being a reasonable implementation. Anyway, the previous version blew up with stack overflow if you appended too many things, which the new version doesn't. minor perf; assume "InProcess" Bug fix; ensure exception protocol is followed Seq.fold --- src/fsharp/FSharp.Core/seq.fs | 1143 +++++++++++++++++---------------- 1 file changed, 587 insertions(+), 556 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 12533201ea2..72d0a46061a 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -108,25 +108,6 @@ namespace Microsoft.FSharp.Collections interface System.IDisposable with member this.Dispose() = this.Dispose() - let map2 f (e1 : IEnumerator<_>) (e2 : IEnumerator<_>) : IEnumerator<_>= - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - upcast - { new MapEnumerator<_>() with - member this.DoMoveNext curr = - let n1 = e1.MoveNext() - let n2 = e2.MoveNext() - if n1 && n2 then - curr <- f.Invoke(e1.Current, e2.Current) - true - else - false - member this.Dispose() = - try - e1.Dispose() - finally - e2.Dispose() - } - let mapi2 f (e1 : IEnumerator<_>) (e2 : IEnumerator<_>) : IEnumerator<_> = let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f) let i = ref (-1) @@ -337,149 +318,6 @@ namespace Microsoft.FSharp.Collections f() } - // Use generators for some implementations of IEnumerables. - // - module Generator = - - open System.Collections - open System.Collections.Generic - - [] - type Step<'T> = - | Stop - | Yield of 'T - | Goto of Generator<'T> - - and Generator<'T> = - abstract Apply: (unit -> Step<'T>) - abstract Disposer: (unit -> unit) option - - let disposeG (g:Generator<'T>) = - match g.Disposer with - | None -> () - | Some f -> f() - - let appG (g:Generator<_>) = - //System.Console.WriteLine("{0}.appG", box g) - let res = g.Apply() - match res with - | Goto(next) -> - Goto(next) - | Yield _ -> - res - | Stop -> - //System.Console.WriteLine("appG: Stop") - disposeG g - res - - // Binding. - // - // We use a type definition to apply a local dynamic optimization. - // We automatically right-associate binding, i.e. push the continuations to the right. - // That is, bindG (bindG G1 cont1) cont2 --> bindG G1 (cont1 o cont2) - // This makes constructs such as the following linear rather than quadratic: - // - // let rec rwalk n = { if n > 0 then - // yield! rwalk (n-1) - // yield n } - - type GenerateThen<'T>(g:Generator<'T>, cont : unit -> Generator<'T>) = - member self.Generator = g - member self.Cont = cont - interface Generator<'T> with - member x.Apply = (fun () -> - match appG g with - | Stop -> - // OK, move onto the generator given by the continuation - Goto(cont()) - - | Yield _ as res -> - res - - | Goto next -> - Goto(GenerateThen<_>.Bind(next,cont))) - member x.Disposer = - g.Disposer - - - static member Bind (g:Generator<'T>, cont) = - match g with - | :? GenerateThen<'T> as g -> GenerateThen<_>.Bind(g.Generator,(fun () -> GenerateThen<_>.Bind (g.Cont(), cont))) - | g -> (new GenerateThen<'T>(g, cont) :> Generator<'T>) - - - let bindG g cont = GenerateThen<_>.Bind(g,cont) - - - // Internal type. Drive an underlying generator. Crucially when the generator returns - // a new generator we simply update our current generator and continue. Thus the enumerator - // effectively acts as a reference cell holding the current generator. This means that - // infinite or large generation chains (e.g. caused by long sequences of append's, including - // possible delay loops) can be referenced via a single enumerator. - // - // A classic case where this arises in this sort of sequence expression: - // let rec data s = { yield s; - // yield! data (s + random()) } - // - // This translates to - // let rec data s = Seq.delay (fun () -> Seq.append (Seq.singleton s) (Seq.delay (fun () -> data (s+random())))) - // - // When you unwind through all the Seq, IEnumerator and Generator objects created, - // you get (data s).GetEnumerator being an "GenerateFromEnumerator(EnumeratorWrappingLazyGenerator(...))" for the append. - // After one element is yielded, we move on to the generator for the inner delay, which in turn - // comes back to be a "GenerateFromEnumerator(EnumeratorWrappingLazyGenerator(...))". - // - // Defined as a type so we can optimize Enumerator/Generator chains in enumerateFromLazyGenerator - // and GenerateFromEnumerator. - - [] - type EnumeratorWrappingLazyGenerator<'T>(g:Generator<'T>) = - let mutable g = g - let mutable curr = None - let mutable finished = false - member e.Generator = g - interface IEnumerator<'T> with - member x.Current= match curr with Some(v) -> v | None -> raise <| System.InvalidOperationException (SR.GetString(SR.moveNextNotCalledOrFinished)) - interface System.Collections.IEnumerator with - member x.Current = box (x :> IEnumerator<_>).Current - member x.MoveNext() = - not finished && - (match appG g with - | Stop -> - curr <- None - finished <- true - false - | Yield(v) -> - curr <- Some(v) - true - | Goto(next) -> - (g <- next) - (x :> IEnumerator).MoveNext()) - member x.Reset() = IEnumerator.noReset() - interface System.IDisposable with - member x.Dispose() = - if not finished then disposeG g - - // Internal type, used to optimize Enumerator/Generator chains - type LazyGeneratorWrappingEnumerator<'T>(e:System.Collections.Generic.IEnumerator<'T>) = - member g.Enumerator = e - interface Generator<'T> with - member g.Apply = (fun () -> - if e.MoveNext() then - Yield(e.Current) - else - Stop) - member g.Disposer= Some(e.Dispose) - - let EnumerateFromGenerator(g:Generator<'T>) = - match g with - | :? LazyGeneratorWrappingEnumerator<'T> as g -> g.Enumerator - | _ -> (new EnumeratorWrappingLazyGenerator<_>(g) :> System.Collections.Generic.IEnumerator<_>) - - let GenerateFromEnumerator (e:System.Collections.Generic.IEnumerator<'T>) = - match e with - | :? EnumeratorWrappingLazyGenerator<'T> as e -> e.Generator - | _ -> (new LazyGeneratorWrappingEnumerator<'T>(e) :> Generator<'T>) namespace Microsoft.FSharp.Core.CompilerServices @@ -804,6 +642,10 @@ namespace Microsoft.FSharp.Collections module SeqComposer = open IEnumerator + type ISeqComponent = + abstract OnComplete : unit -> unit + abstract OnDispose : unit -> unit + module Helpers = // used for performance reasons; these are not recursive calls, so should be safe let inline avoidTailCall x = @@ -816,468 +658,654 @@ namespace Microsoft.FSharp.Collections let inline UpcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) let inline UpcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) let inline UpcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) + let inline UpcastISeqComponent (t:#ISeqComponent) : ISeqComponent = (# "" t : ISeqComponent #) - type [] SeqComponent<'T,'U> () = - abstract ProcessNext : input:'T * halt:byref * output:byref<'U> -> bool - abstract OnComplete : unit -> unit + type SeqProcessNextStates = + | InProcess = 0 + | NotStarted = 1 + | Finished = 2 - abstract Composer : SeqComponent<'U,'V> -> SeqComponent<'T,'V> + type Result<'T>() = + let mutable halted = false - abstract ComposeWithMap<'S> : Map<'S,'T> -> SeqComponent<'S,'U> - abstract ComposeWithFilter : Filter<'T> -> SeqComponent<'T,'U> - abstract ComposeWithFilterThenMap<'S> : FilterThenMap<'S,'T> -> SeqComponent<'S,'U> - abstract ComposeWithMapThenFilter<'S> : MapThenFilter<'S,'T> -> SeqComponent<'S,'U> - abstract ComposeWithSkip : Skip<'T> -> SeqComponent<'T,'U> + member val SeqState = SeqProcessNextStates.NotStarted with get, set - default __.OnComplete () = () + member __.StopFurtherProcessing () = halted <- true + member __.Halted = halted - default first.Composer (second:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Composed (first, second) + member val Current = Unchecked.defaultof<'T> with get, set - default second.ComposeWithMap<'S> (first:Map<'S,'T>) : SeqComponent<'S,'U> = upcast Composed (first, second) - default second.ComposeWithFilter (first:Filter<'T>) : SeqComponent<'T,'U> = upcast Composed (first, second) - default second.ComposeWithFilterThenMap<'S> (first:FilterThenMap<'S,'T>) : SeqComponent<'S,'U> = upcast Composed (first, second) - default second.ComposeWithMapThenFilter<'S> (first:MapThenFilter<'S,'T>) : SeqComponent<'S,'U> = upcast Composed (first, second) - default second.ComposeWithSkip (first:Skip<'T>) : SeqComponent<'T,'U> = upcast Composed (first, second) + let seqComponentTail = + { new ISeqComponent with + member __.OnComplete() = () + member __.OnDispose() = () } - and Composed<'T,'U,'V> (first:SeqComponent<'T,'U>, second:SeqComponent<'U,'V>) = - inherit SeqComponent<'T,'V>() + type [] SeqComponentFactory<'T,'U> () = + abstract Create<'V> : Result<'V> -> SeqComponent<'U,'V> -> SeqComponent<'T,'V> - override __.ProcessNext (input:'T, halted:byref, output:byref<'V>) :bool = - let mutable temp = Unchecked.defaultof<'U> - if first.ProcessNext (input, &halted, &temp) then - second.ProcessNext (temp, &halted, &output) - else - false + and ComposedFactory<'T,'U,'V> (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>) = + inherit SeqComponentFactory<'T,'V> () + override __.Create<'W> (result:Result<'W>) (next:SeqComponent<'V,'W>) : SeqComponent<'T,'W> = first.Create result (second.Create result next) - override __.Composer (next:SeqComponent<'V,'W>) : SeqComponent<'T,'W> = - upcast Composed (first, second.Composer next) + and ChooseFactory<'T,'U> (filter:'T->option<'U>) = + inherit SeqComponentFactory<'T,'U> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Choose (filter, next) - override __.OnComplete () = - first.OnComplete () - second.OnComplete () + and FilterFactory<'T> (filter:'T->bool) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = next.CreateFilter filter - and Map<'T,'U> (map:'T->'U) = - inherit SeqComponent<'T,'U>() + and MapFactory<'T,'U> (map:'T->'U) = + inherit SeqComponentFactory<'T,'U> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = next.CreateMap map - override first.Composer (second:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = - second.ComposeWithMap first + and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = + inherit SeqComponentFactory<'First,'U> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map2First (map, input2, result, next) - override second.ComposeWithMap<'S> (first:Map<'S,'T>) : SeqComponent<'S,'U> = - upcast Map (first.Map >> second.Map) - - override second.ComposeWithFilter (first:Filter<'T>) : SeqComponent<'T,'U> = - upcast FilterThenMap (first.Filter, second.Map) + and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = + inherit SeqComponentFactory<'Second,'U> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'Second,'V> = upcast Map2Second (map, input1, result, next) - override second.ComposeWithFilterThenMap<'S> (first:FilterThenMap<'S,'T>) : SeqComponent<'S,'U> = - upcast FilterThenMap (first.Filter, first.Map >> second.Map) + and MapiFactory<'T,'U> (mapi:int->'T->'U) = + inherit SeqComponentFactory<'T,'U> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Mapi (mapi, next) - override __.ProcessNext (input:'T, halted:byref, output:byref<'U>) : bool = - output <- map input - true + and PairwiseFactory<'T> () = + inherit SeqComponentFactory<'T,'T*'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T*'T,'V>) : SeqComponent<'T,'V> = upcast Pairwise next - member __.Map : 'T->'U = map + and SkipFactory<'T> (count:int) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Skip (count, next) - and Mapi<'T,'U> (mapi:int->'T->'U) = - inherit SeqComponent<'T,'U>() + and SkipWhileFactory<'T> (perdicate:'T->bool) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast SkipWhile (perdicate, next) - let mutable idx = 0 + and TakeWhileFactory<'T> (perdicate:'T->bool) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast TakeWhile (perdicate, result, next) - override __.ProcessNext (input:'T, halted:byref, output:byref<'U>) : bool = - output <- mapi idx input - idx <- idx + 1 - true + and TakeFactory<'T> (count:int) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Take (count, result, next) + + and [] SeqComponent<'T,'U> (next:ISeqComponent) = + abstract ProcessNext : input:'T -> bool - member __.Mapi : int->'T->'U = mapi + // Seq.init(Infinite)? lazily uses Current. The only SeqComposer component that can do that is Skip + // and it can only do it at the start of a sequence + abstract Skipping : unit -> bool - and Filter<'T> (filter:'T->bool) = - inherit SeqComponent<'T,'T>() + abstract CreateMap<'S> : map:('S->'T) -> SeqComponent<'S,'U> + abstract CreateFilter : filter:('T->bool) -> SeqComponent<'T,'U> - override first.Composer (second:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = - second.ComposeWithFilter first + interface ISeqComponent with + member __.OnComplete () = next.OnComplete () + member __.OnDispose () = next.OnDispose () - override second.ComposeWithMap<'S> (first:Map<'S,'T>) : SeqComponent<'S,'T> = - upcast MapThenFilter (first.Map, second.Filter) + default __.Skipping () = false - override second.ComposeWithFilter (first:Filter<'T>) : SeqComponent<'T,'T> = - upcast Filter (Helpers.ComposeFilter first.Filter second.Filter) + default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) + default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) - override second.ComposeWithMapThenFilter<'S> (first:MapThenFilter<'S,'T>) : SeqComponent<'S,'T> = - upcast MapThenFilter (first.Map, Helpers.ComposeFilter first.Filter second.Filter) + and Choose<'T,'U,'V> (choose:'T->option<'U>, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + match choose input with + | Some value -> Helpers.avoidTailCall (next.ProcessNext value) + | None -> false - override __.ProcessNext (input:'T, halted:byref, output:byref<'T>) : bool = + and Filter<'T,'V> (filter:'T->bool, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) + + override __.ProcessNext (input:'T) : bool = if filter input then - output <- input - true + Helpers.avoidTailCall (next.ProcessNext input) + else + false + + and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + if filter input then + Helpers.avoidTailCall (next.ProcessNext (map input)) else false - member __.Filter :'T->bool = filter + and Map<'T,'U,'V> (map:'T->'U, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'T,'V>(next) - and MapThenFilter<'T,'U> (map:'T->'U, filter:'U->bool) = - inherit SeqComponent<'T,'U>() + override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) - override __.ProcessNext (input:'T, halted:byref, output:byref<'U>) :bool = - output <- map input - Helpers.avoidTailCall (filter output) + override __.ProcessNext (input:'T) : bool = + Helpers.avoidTailCall (next.ProcessNext (map input)) - override first.Composer (second:SeqComponent<'U,'V>):SeqComponent<'T,'V> = - second.ComposeWithMapThenFilter first + and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'First,'V>(next) - member __.Map : 'T->'U = map - member __.Filter : 'U->bool = filter + let input2 = enumerable2.GetEnumerator () + let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map - and FilterThenMap<'T,'U> (filter:'T->bool, map:'T->'U) = - inherit SeqComponent<'T,'U>() + override __.ProcessNext (input:'First) : bool = + if input2.MoveNext () then + Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) + else + result.StopFurtherProcessing () + false - override __.ProcessNext (input:'T, halted:byref, output:byref<'U>) : bool = - if filter input then - output <- map input - true + interface ISeqComponent with + override __.OnDispose () = + input2.Dispose () + (Helpers.UpcastISeqComponent next).OnDispose () + + and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:Result<'V>, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'Second,'V>(next) + + let input1 = enumerable1.GetEnumerator () + let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map + + override __.ProcessNext (input:'Second) : bool = + if input1.MoveNext () then + Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) + else + result.StopFurtherProcessing () + false + + interface ISeqComponent with + override __.OnDispose () = + input1.Dispose () + (Helpers.UpcastISeqComponent next).OnDispose () + + and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + let u = map input + if filter u then + Helpers.avoidTailCall (next.ProcessNext u) else false - override first.Composer (second:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = second.ComposeWithFilterThenMap first + and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'T,'V>(next) - member __.Filter : 'T->bool = filter - member __.Map : 'T->'U = map + let mutable idx = 0 + let mapi' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt mapi - and Pairwise<'T> () = - inherit SeqComponent<'T,'T*'T>() + override __.ProcessNext (input:'T) : bool = + idx <- idx + 1 + Helpers.avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) + + and Pairwise<'T,'V> (next:SeqComponent<'T*'T,'V>) = + inherit SeqComponent<'T,'V>(next) let mutable isFirst = true let mutable lastValue = Unchecked.defaultof<'T> - override __.ProcessNext (input:'T, halted:byref, output:byref<'T*'T>) : bool = + override __.ProcessNext (input:'T) : bool = if isFirst then lastValue <- input isFirst <- false false else - output <- lastValue, input + let currentPair = lastValue, input lastValue <- input - true + Helpers.avoidTailCall (next.ProcessNext currentPair) - and Skip<'T> (skipCount:int) = - inherit SeqComponent<'T,'T>() + and Skip<'T,'V> (skipCount:int, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let mutable count = 0 - override first.Composer (second:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = - second.ComposeWithSkip first - - override second.ComposeWithSkip (first:Skip<'T>) : SeqComponent<'T,'T> = - if Int32.MaxValue - first.SkipCount - second.SkipCount > 0 then - upcast Skip (first.SkipCount + second.SkipCount) + override __.Skipping () = + if count < skipCount then + count <- count + 1 + true else - upcast Composed (first, second) + false - override __.ProcessNext (input:'T, halted:byref, output:byref<'T>) : bool = + override __.ProcessNext (input:'T) : bool = if count < skipCount then count <- count + 1 false else - output <- input - true + Helpers.avoidTailCall (next.ProcessNext input) - override __.OnComplete () = - if count < skipCount then - let x = skipCount - count - invalidOpFmt "tried to skip {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - - member __.SkipCount = skipCount + interface ISeqComponent with + override __.OnComplete () = + if count < skipCount then + let x = skipCount - count + invalidOpFmt "tried to skip {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + (Helpers.UpcastISeqComponent next).OnComplete () - and Take<'T> (takeCount:int) = - inherit SeqComponent<'T,'T>() + and SkipWhile<'T,'V> (predicate:'T->bool, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) - let mutable count = 0 + let mutable skip = true - override second.ComposeWithSkip (first:Skip<'T>) : SeqComponent<'T,'T> = - if Int32.MaxValue - first.SkipCount - second.TakeCount > 0 then - upcast SkipThenTake (first.SkipCount, first.SkipCount+second.TakeCount) + override __.ProcessNext (input:'T) : bool = + if skip then + skip <- predicate input + if skip then + false + else + Helpers.avoidTailCall (next.ProcessNext input) else - upcast Composed (first, second) + Helpers.avoidTailCall (next.ProcessNext input) + + and Take<'T,'V> (takeCount:int, result:Result<'V>, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable count = 0 - override __.ProcessNext (input:'T, halted:byref, output:byref<'T>) : bool = + override __.ProcessNext (input:'T) : bool = if count < takeCount then count <- count + 1 - output <- input - halted <- count = takeCount - true + if count = takeCount then + result.StopFurtherProcessing () + next.ProcessNext input else - halted <- true + result.StopFurtherProcessing () false - override __.OnComplete () = - if count < takeCount then - let x = takeCount - count - invalidOpFmt "tried to take {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + interface ISeqComponent with + override __.OnComplete () = + if count < takeCount then + let x = takeCount - count + invalidOpFmt "tried to take {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + (Helpers.UpcastISeqComponent next).OnComplete () - member __.TakeCount = takeCount + and TakeWhile<'T,'V> (predicate:'T->bool, result:Result<'V>, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) - and SkipThenTake<'T> (startIdx:int, endIdx:int) = - inherit SeqComponent<'T,'T>() - - let mutable count = 0 - - override __.ProcessNext (input:'T, halted:byref, output:byref<'T>) : bool = - if count < startIdx then - count <- count + 1 - false - elif count < endIdx then - count <- count + 1 - output <- input - halted <- count = endIdx - true + override __.ProcessNext (input:'T) : bool = + if predicate input then + next.ProcessNext input else - halted <- true + result.StopFurtherProcessing () false - override __.OnComplete () = - if count < startIdx then - let x = startIdx - count - invalidOpFmt "tried to skip {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - elif count < endIdx then - let x = endIdx - count - invalidOpFmt "tried to take {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - - and SkipWhile<'T> (predicate: 'T -> bool) = - inherit SeqComponent<'T,'T>() + and Tail<'T> (result:Result<'T>) = + inherit SeqComponent<'T,'T>(seqComponentTail) - let mutable skip = true + override __.ProcessNext (input:'T) : bool = + result.Current <- input + true - override __.ProcessNext (input:'T, halted:byref, output:byref<'T>) : bool = - if skip then - skip <- predicate input - if skip then - false - else - output <- input - true - else - output <- input - true + module Enumerable = + [] + type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ISeqComponent) = + interface IDisposable with + member __.Dispose() : unit = + seqComponent.OnDispose () + + interface IEnumerator with + member this.Current : obj = box ((Helpers.UpcastEnumerator this)).Current + member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)" + member __.Reset () : unit = noReset () + + interface IEnumerator<'T> with + member __.Current = + if result.SeqState = SeqProcessNextStates.InProcess then result.Current + else + match result.SeqState with + | SeqProcessNextStates.NotStarted -> notStarted() + | SeqProcessNextStates.Finished -> alreadyFinished() + | _ -> failwith "library implementation error: all states should have been handled" - and TakeWhile<'T> (predicate: 'T -> bool) = - inherit SeqComponent<'T,'T>() + and [] EnumerableBase<'T> () = + abstract member Compose<'U> : (SeqComponentFactory<'T,'U>) -> IEnumerable<'U> + abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> + abstract member Fold<'State> : folder:('State->'T->'State) -> state:'State -> 'State - override __.ProcessNext (input:'T, halted:byref, output:byref<'T>) : bool = - if predicate input then - output <- input - true - else - halted <- true - false + default this.Append source = Helpers.UpcastEnumerable (AppendEnumerable [this; source]) - and Choose<'T, 'U> (choose:'T->'U option) = - inherit SeqComponent<'T,'U>() + interface IEnumerable with + member this.GetEnumerator () : IEnumerator = + let genericEnumerable = Helpers.UpcastEnumerable this + let genericEnumerator = genericEnumerable.GetEnumerator () + Helpers.UpcastEnumeratorNonGeneric genericEnumerator - override __.ProcessNext (input:'T, halted:byref, output:byref<'U>) : bool = - match choose input with - | Some value -> output <- value - true - | None -> false + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = failwith "library implementation error: derived class should implement (should be abstract)" - type SeqProcessNextStates = - | NotStarted = 1 - | Finished = 2 - | InProcess = 3 + and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + inherit EnumeratorBase<'U>(result, seqComponent) - type SeqComposedEnumerator<'T,'U>(enumerator:IEnumerator<'T>, t2u:SeqComponent<'T,'U>) = - let mutable state = SeqProcessNextStates.NotStarted - let mutable current = Unchecked.defaultof<'U> - let mutable halted = false + let rec moveNext () = + if (not result.Halted) && source.MoveNext () then + if seqComponent.ProcessNext source.Current then + true + else + moveNext () + else + result.SeqState <- SeqProcessNextStates.Finished + (Helpers.UpcastISeqComponent seqComponent).OnComplete () + false - let mutable source = enumerator + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext () - let rec moveNext () = - if (not halted) && source.MoveNext () then - if t2u.ProcessNext (source.Current, &halted, ¤t) then - true + interface IDisposable with + member __.Dispose() = + source.Dispose () + (Helpers.UpcastISeqComponent seqComponent).OnDispose () + + and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqComponentFactory<'T,'U>) = + inherit EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Helpers.UpcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (Tail result), result)) + + override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = + Helpers.UpcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory (current, next))) + + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let enumerator = enumerable.GetEnumerator () + let result = Result<'U> () + + let components = current.Create result (Tail result) + + let mutable state = initialState + while (not result.Halted) && (enumerator.MoveNext ()) do + if components.ProcessNext (enumerator.Current) then + state <- folder'.Invoke (state, result.Current) + + state + + and AppendEnumerator<'T> (sources:list>) = + let sources = sources |> List.rev + + let mutable state = SeqProcessNextStates.NotStarted + let mutable remaining = sources.Tail + let mutable active = sources.Head.GetEnumerator () + + let rec moveNext () = + if active.MoveNext () then true else + match remaining with + | [] -> false + | hd :: tl -> + active.Dispose () + active <- hd.GetEnumerator () + remaining <- tl + + moveNext () + + interface IEnumerator<'T> with + member __.Current = + if state = SeqProcessNextStates.InProcess then active.Current + else + match state with + | SeqProcessNextStates.NotStarted -> notStarted() + | SeqProcessNextStates.Finished -> alreadyFinished() + | _ -> failwith "library implementation error: all states should have been handled" + + interface IEnumerator with + member this.Current = box ((Helpers.UpcastEnumerator this)).Current + member __.MoveNext () = + state <- SeqProcessNextStates.InProcess moveNext () - else - state <- SeqProcessNextStates.Finished - t2u.OnComplete () - false - - interface IDisposable with - member __.Dispose():unit = - match source with - | null -> () - | _ -> source.Dispose (); source <- Unchecked.defaultof<_> + member __.Reset () = noReset () + + interface IDisposable with + member __.Dispose() = + active.Dispose () + + and AppendEnumerable<'T> (sources:list>) = + inherit EnumerableBase<'T>() + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = + Helpers.UpcastEnumerator (new AppendEnumerator<_> (sources)) + + override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = + Helpers.UpcastEnumerable (Enumerable<'T,'V>(this, next)) + + override this.Append source = + Helpers.UpcastEnumerable (AppendEnumerable (source :: sources)) + + override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let enumerable = Helpers.UpcastEnumerable (AppendEnumerable sources) + let enumerator = enumerable.GetEnumerator () + + let mutable state = initialState + while enumerator.MoveNext () do + state <- folder'.Invoke (state, enumerator.Current) + + state + + module Array = + type Enumerator<'T,'U>(array:array<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + + let mutable idx = 0 + + let rec moveNext () = + if (not result.Halted) && idx < array.Length then + idx <- idx+1 + if seqComponent.ProcessNext array.[idx-1] then + true + else + moveNext () + else + result.SeqState <- SeqProcessNextStates.Finished + (Helpers.UpcastISeqComponent seqComponent).OnComplete () + false - interface IEnumerator with - member this.Current : obj = box (Helpers.UpcastEnumerator this).Current - member __.MoveNext () = - state <- SeqProcessNextStates.InProcess - moveNext () - member __.Reset () : unit = noReset () - - interface IEnumerator<'U> with - member __.Current = - match state with - | SeqProcessNextStates.NotStarted -> notStarted() - | SeqProcessNextStates.Finished -> alreadyFinished() - | _ -> current - - type ArrayComposedEnumerator<'T,'U>(array:array<'T>, t2u:SeqComponent<'T,'U>) = - let mutable state = SeqProcessNextStates.NotStarted - let mutable current = Unchecked.defaultof<'U> - let mutable halted = false + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext () - let mutable idx = 0 + type Enumerable<'T,'U>(array:array<'T>, current:SeqComponentFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Helpers.UpcastEnumerator (new Enumerator<'T,'U>(array, current.Create result (Tail result), result)) + + override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = + Helpers.UpcastEnumerable (new Enumerable<'T,'V>(array, ComposedFactory (current, next))) + + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let mutable idx = 0 + let result = Result<'U> () + let components = current.Create result (Tail result) + + let mutable state = initialState + while (not result.Halted) && (idx < array.Length) do + if components.ProcessNext array.[idx] then + state <- folder'.Invoke (state, result.Current) + idx <- idx + 1 + + state + + module List = + type Enumerator<'T,'U>(alist:list<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + + let mutable list = alist + + let rec moveNext current = + match result.Halted, current with + | false, head::tail -> + if seqComponent.ProcessNext head then + list <- tail + true + else + moveNext tail + | _ -> + result.SeqState <- SeqProcessNextStates.Finished + (Helpers.UpcastISeqComponent seqComponent).OnComplete () + false - let rec moveNext () = - if (not halted) && idx < array.Length then - idx <- idx+1 - if t2u.ProcessNext (array.[idx-1], &halted, ¤t) then - true - else - moveNext () + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext list + + type Enumerable<'T,'U>(alist:list<'T>, current:SeqComponentFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Helpers.UpcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (Tail result), result)) + + override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = + Helpers.UpcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory (current, next))) + + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let result = Result<'U> () + let components = current.Create result (Tail result) + + let rec fold state lst = + match result.Halted, lst with + | true, _ + | false, [] -> state + | false, hd :: tl -> + if components.ProcessNext hd then + fold (folder'.Invoke (state, result.Current)) tl + else + fold state tl + + fold initialState alist + + module Init = + // The original implementation of "init" delayed the calculation of Current, and so it was possible + // to do MoveNext without it's value being calculated. + // I can imagine only two scenerios where that is possibly sane, although a simple solution is readily + // at hand in both cases. The first is that of an expensive generator function, where you skip the + // first n elements. The simple solution would have just been to have a map ((+) n) as the first operation + // instead. The second case would be counting elements, but that is only of use if you're not filtering + // or mapping or doing anything else (as that would cause Current to be evaluated!) and + // so you already know what the count is!! Anyway, someone thought it was a good idea, so + // I have had to add an extra function that is used in Skip to determine if we are touching + // Current or not. + + let getTerminatingIdx (count:Nullable) = + // we are offset by 1 to allow for values going up to System.Int32.MaxValue + // System.Int32.MaxValue is an illegal value for the "infinite" sequence + if count.HasValue then + count.Value - 1 else - state <- SeqProcessNextStates.Finished - t2u.OnComplete () - false + System.Int32.MaxValue - interface IDisposable with - member __.Dispose() : unit = () + type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:SeqComponent<'T,'U>, signal:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) - interface IEnumerator with - member this.Current : obj = box ((Helpers.UpcastEnumerator this)).Current - member __.MoveNext () = - state <- SeqProcessNextStates.InProcess - moveNext () - member __.Reset () : unit = noReset () - - interface IEnumerator<'U> with - member __.Current = - match state with - | SeqProcessNextStates.NotStarted -> notStarted() - | SeqProcessNextStates.Finished -> alreadyFinished() - | _ -> current - - type ListComposedEnumerator<'T,'U>(alist:list<'T>, t2u:SeqComponent<'T,'U>) = - let mutable state = SeqProcessNextStates.NotStarted - let mutable current = Unchecked.defaultof<'U> - let mutable halted = false + let terminatingIdx = + getTerminatingIdx count - let mutable list = alist + let mutable maybeSkipping = true + let mutable idx = -1 - let rec moveNext () = - match halted, list with - | false, head::tail -> - list <- tail - if t2u.ProcessNext (head, &halted, ¤t) then - true - else - moveNext () - | _ -> state <- SeqProcessNextStates.Finished - t2u.OnComplete () - false + let rec moveNext () = + if (not signal.Halted) && idx < terminatingIdx then + idx <- idx + 1 - interface IDisposable with - member __.Dispose() : unit = () + if maybeSkipping then + // Skip can only is only checked at the start of the sequence, so once + // triggered, we stay triggered. + maybeSkipping <- seqComponent.Skipping () + + if maybeSkipping then + moveNext () + elif seqComponent.ProcessNext (f idx) then + true + else + moveNext () + elif (not signal.Halted) && idx = System.Int32.MaxValue then + raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) + else + signal.SeqState <- SeqProcessNextStates.Finished + (Helpers.UpcastISeqComponent seqComponent).OnComplete () + false - interface IEnumerator with - member this.Current : obj = box (this:>IEnumerator<'U>).Current - member __.MoveNext () = - state <- SeqProcessNextStates.InProcess - moveNext () - member __.Reset () : unit = noReset () - - interface IEnumerator<'U> with - member __.Current = - match state with - | SeqProcessNextStates.NotStarted -> notStarted() - | SeqProcessNextStates.Finished -> alreadyFinished() - | _ -> current - - [] - type ComposableEnumerable<'T> () = - abstract member Compose<'U> : (unit -> SeqComponent<'T,'U>) -> IEnumerable<'U> - - type SeqEnumerable<'T,'U>(enumerable:IEnumerable<'T>, current:unit->SeqComponent<'T,'U>) = - inherit ComposableEnumerable<'U>() - - let getEnumerator () : IEnumerator<'U> = - Helpers.UpcastEnumerator (new SeqEnumeratorEnumerator<'T,'U>(enumerable.GetEnumerator(), current ())) - - interface IEnumerable with - member this.GetEnumerator () : IEnumerator = Helpers.UpcastEnumeratorNonGeneric (getEnumerator ()) - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = getEnumerator () - - override __.Compose (next:unit->SeqComponent<'U,'V>) : IEnumerable<'V> = - Helpers.UpcastEnumerable (new SeqEnumerable<'T,'V>(enumerable, fun () -> (current ()).Composer (next ()))) - -// interface ISeqEnumerable<'U> with -// member this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = -// let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder -// -// let enumerator = enumerable.GetEnumerator () -// let components = current () -// let mutable output = Unchecked.defaultof<'U> -// let mutable halt = false -// -// let mutable state = initialState -// while (not halt) && enumerator.MoveNext () do -// if components.ProcessNext (enumerator.Current, &halt, &output) then -// state <- folder'.Invoke (state, output) -// -// state - - type SeqArrayEnumerable<'T,'U>(array:array<'T>, current:unit->SeqComponent<'T,'U>) = - inherit ComposableEnumerable<'U>() - - let getEnumerator () : IEnumerator<'U> = - Helpers.UpcastEnumerator (new SeqArrayEnumerator<'T,'U>(array, current ())) - - interface IEnumerable with - member this.GetEnumerator () : IEnumerator = Helpers.UpcastEnumeratorNonGeneric (getEnumerator ()) - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = getEnumerator () - - override __.Compose (next:unit->SeqComponent<'U,'V>) : IEnumerable<'V> = - Helpers.UpcastEnumerable (new SeqArrayEnumerable<'T,'V>(array, fun () -> (current ()).Composer (next ()))) - -// interface ISeqEnumerable<'U> with -// member this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = -// let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder -// -// let mutable idx = 0 -// let components = current () -// let mutable current = Unchecked.defaultof<'U> -// let mutable halt = false -// -// let mutable state = initialState -// while (not halt) && idx < array.Length do -// if components.ProcessNext (array.[idx], &halt, ¤t) then -// state <- folder'.Invoke(state, current) -// idx <- idx + 1 -// -// state - - type SeqListEnumerable<'T,'U>(alist:list<'T>, current:unit->SeqComponent<'T,'U>) = - inherit ComposableEnumerable<'U>() - - let getEnumerator () : IEnumerator<'U> = - upcast (new ListComposedEnumerator<'T,'U>(alist, current ())) - - interface IEnumerable with - member this.GetEnumerator () : IEnumerator = upcast (getEnumerator ()) - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = getEnumerator () - - override __.Compose (next:unit->SeqComponent<'U,'V>) : IEnumerable<'V> = - upcast new SeqListEnumerable<'T,'V>(alist, fun () -> (current ()).Composer (next ())) + interface IEnumerator with + member __.MoveNext () = + signal.SeqState <- SeqProcessNextStates.InProcess + moveNext () + type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqComponentFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Helpers.UpcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (Tail result), result)) + + override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = + Helpers.UpcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory (current, next))) + + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let result = Result<'U> () + let components = current.Create result (Tail result) + + let mutable idx = -1 + let terminatingIdx = getTerminatingIdx count + + let mutable maybeSkipping = true + + let mutable state = initialState + while (not result.Halted) && (idx < terminatingIdx) do + if maybeSkipping then + maybeSkipping <- components.Skipping () + + if (not maybeSkipping) && (components.ProcessNext (f (idx+1))) then + state <- folder'.Invoke (state, result.Current) + + idx <- idx + 1 + + state + + type EnumerableDecider<'T>(count:Nullable, f:int->'T) = + inherit Enumerable.EnumerableBase<'T>() + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = + // we defer back to the original implementation as, as it's quite idiomatic in it's decision + // to calculate Current in a lazy fashion. I doubt anyone is really using this functionality + // in the way presented, but it's possible. + upto (if count.HasValue then Some (count.Value-1) else None) f + + override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = + Helpers.UpcastEnumerable (Enumerable<'T,'V>(count, f, next)) + + override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let enumerator = (Helpers.UpcastEnumerable this).GetEnumerator () + + let mutable state = initialState + while enumerator.MoveNext () do + state <- folder'.Invoke (state, enumerator.Current) + + state #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions @@ -1300,12 +1328,14 @@ namespace Microsoft.FSharp.Collections let empty<'T> = (EmptyEnumerable :> seq<'T>) [] - let initInfinite f = mkSeq (fun () -> IEnumerator.upto None f) + let initInfinite<'T> (f:int->'T) : IEnumerable<'T> = + SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.Init.EnumerableDecider<'T>(Nullable (), f)) [] - let init count f = + let init<'T> (count:int) (f:int->'T) : IEnumerable<'T> = if count < 0 then invalidArgInputMustBeNonNegative "count" count - mkSeq (fun () -> IEnumerator.upto (Some (count-1)) f) + elif count = 0 then empty else + SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.Init.EnumerableDecider<'T>(Nullable count, f)) [] let iter f (source : seq<'T>) = @@ -1401,28 +1431,25 @@ namespace Microsoft.FSharp.Collections let private seqFactory createSeqComponent (source:seq<'T>) = checkNonNull "source" source match source with - | :? SeqComposer.ComposableEnumerable<'T> as s -> s.Compose createSeqComponent - | :? array<'T> as a -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.SeqArrayEnumerable<_,_>(a, createSeqComponent)) - | :? list<'T> as a -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.SeqListEnumerable<_,_>(a, createSeqComponent)) - | _ -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.SeqEnumerable<_,_>(source, createSeqComponent)) - - let private seqFactoryForImmutable seqComponent (source:seq<'T>) = - source |> seqFactory (fun () -> seqComponent) + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Compose createSeqComponent + | :? array<'T> as a -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.Array.Enumerable<_,_>(a, createSeqComponent)) + | :? list<'T> as a -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.List.Enumerable<_,_>(a, createSeqComponent)) + | _ -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.Enumerable.Enumerable<_,_>(source, createSeqComponent)) [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = - source |> seqFactoryForImmutable (SeqComposer.Filter f) + source |> seqFactory (SeqComposer.FilterFactory f) [] let where f source = filter f source [] let map<'T,'U> (f:'T->'U) (source:seq<'T>) : seq<'U> = - source |> seqFactoryForImmutable (SeqComposer.Map f) + source |> seqFactory (SeqComposer.MapFactory f) [] let mapi f source = - source |> seqFactory (fun () -> upcast SeqComposer.Mapi f) + source |> seqFactory (SeqComposer.MapiFactory f) [] let mapi2 f source1 source2 = @@ -1431,10 +1458,12 @@ namespace Microsoft.FSharp.Collections revamp2 (IEnumerator.mapi2 f) source1 source2 [] - let map2 f source1 source2 = + let map2<'T,'U,'V> (f:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = checkNonNull "source1" source1 checkNonNull "source2" source2 - revamp2 (IEnumerator.map2 f) source1 source2 + match source1 with + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Compose (SeqComposer.Map2FirstFactory (f, source2)) + | _ -> source2 |> seqFactory (SeqComposer.Map2SecondFactory (f, source1)) [] let map3 f source1 source2 source3 = @@ -1445,7 +1474,7 @@ namespace Microsoft.FSharp.Collections [] let choose f source = - source |> seqFactoryForImmutable (SeqComposer.Choose f) + source |> seqFactory (SeqComposer.ChooseFactory f) [] let indexed source = @@ -1508,7 +1537,7 @@ namespace Microsoft.FSharp.Collections if count < 0 then invalidArgInputMustBeNonNegative "count" count (* Note: don't create or dispose any IEnumerable if n = 0 *) if count = 0 then empty else - source |> seqFactory (fun () -> upcast SeqComposer.Take count) + source |> seqFactory (SeqComposer.TakeFactory count) [] let isEmpty (source : seq<'T>) = @@ -1542,14 +1571,17 @@ namespace Microsoft.FSharp.Collections state [] - let fold<'T,'State> f (x:'State) (source : seq<'T>) = + let fold<'T,'State> f (x:'State) (source:seq<'T>) = checkNonNull "source" source - use e = source.GetEnumerator() - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let mutable state = x - while e.MoveNext() do - state <- f.Invoke(state, e.Current) - state + match source with + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Fold f x + | _ -> + use e = source.GetEnumerator() + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) + let mutable state = x + while e.MoveNext() do + state <- f.Invoke(state, e.Current) + state [] let fold2<'T1,'T2,'State> f (state:'State) (source1: seq<'T1>) (source2: seq<'T2>) = @@ -1578,9 +1610,6 @@ namespace Microsoft.FSharp.Collections state <- f.Invoke(state, e.Current) state - let fromGenerator f = mkSeq(fun () -> Generator.EnumerateFromGenerator (f())) - let toGenerator (ie : seq<_>) = Generator.GenerateFromEnumerator (ie.GetEnumerator()) - [] let replicate count x = System.Linq.Enumerable.Repeat(x,count) @@ -1589,7 +1618,9 @@ namespace Microsoft.FSharp.Collections let append (source1: seq<'T>) (source2: seq<'T>) = checkNonNull "source1" source1 checkNonNull "source2" source2 - fromGenerator(fun () -> Generator.bindG (toGenerator source1) (fun () -> toGenerator source2)) + match source1 with + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Append source2 + | _ -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.Enumerable.AppendEnumerable<_>([source2; source1])) [] @@ -1689,7 +1720,7 @@ namespace Microsoft.FSharp.Collections [] let pairwise<'T> (source:seq<'T>) : seq<'T*'T> = - source |> seqFactory (fun () -> upcast SeqComposer.Pairwise ()) + source |> seqFactory (SeqComposer.PairwiseFactory ()) [] let scan<'T,'State> f (z:'State) (source : seq<'T>) = @@ -2119,15 +2150,15 @@ namespace Microsoft.FSharp.Collections *) [] let takeWhile p (source: seq<_>) = - source |> seqFactory (fun () -> upcast SeqComposer.TakeWhile p) + source |> seqFactory (SeqComposer.TakeWhileFactory p) [] let skip count (source: seq<_>) = - source |> seqFactory (fun () -> upcast SeqComposer.Skip count) + source |> seqFactory (SeqComposer.SkipFactory count) [] let skipWhile p (source: seq<_>) = - source |> seqFactory (fun () -> upcast SeqComposer.SkipWhile p) + source |> seqFactory (SeqComposer.SkipWhileFactory p) [] let forall2 p (source1: seq<_>) (source2: seq<_>) = From c05e22a7b1defa8e1dcdc6b07cb96aa0a7ea73a7 Mon Sep 17 00:00:00 2001 From: liboz Date: Tue, 11 Oct 2016 22:28:24 +0200 Subject: [PATCH 06/59] fix typo truncate using inheritance for take --- src/fsharp/FSharp.Core/seq.fs | 56 +++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 72d0a46061a..9336b1bfd7f 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -719,17 +719,21 @@ namespace Microsoft.FSharp.Collections inherit SeqComponentFactory<'T,'T> () override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Skip (count, next) - and SkipWhileFactory<'T> (perdicate:'T->bool) = + and SkipWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast SkipWhile (perdicate, next) + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast SkipWhile (predicate, next) - and TakeWhileFactory<'T> (perdicate:'T->bool) = + and TakeWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast TakeWhile (perdicate, result, next) + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast TakeWhile (predicate, result, next) and TakeFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Take (count, result, next) + + and TruncateFactory<'T> (count:int) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Truncate (count, result, next) and [] SeqComponent<'T,'U> (next:ISeqComponent) = abstract ProcessNext : input:'T -> bool @@ -901,24 +905,12 @@ namespace Microsoft.FSharp.Collections Helpers.avoidTailCall (next.ProcessNext input) and Take<'T,'V> (takeCount:int, result:Result<'V>, next:SeqComponent<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable count = 0 - - override __.ProcessNext (input:'T) : bool = - if count < takeCount then - count <- count + 1 - if count = takeCount then - result.StopFurtherProcessing () - next.ProcessNext input - else - result.StopFurtherProcessing () - false + inherit Truncate<'T, 'V>(takeCount, result, next) interface ISeqComponent with - override __.OnComplete () = - if count < takeCount then - let x = takeCount - count + override this.OnComplete () = + if this.Count < takeCount then + let x = takeCount - this.Count invalidOpFmt "tried to take {0} {1} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] (Helpers.UpcastISeqComponent next).OnComplete () @@ -940,6 +932,23 @@ namespace Microsoft.FSharp.Collections result.Current <- input true + and Truncate<'T,'V> (truncateCount:int, result:Result<'V>, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable count = 0 + + member __.Count = count + + override __.ProcessNext (input:'T) : bool = + if count < truncateCount then + count <- count + 1 + if count = truncateCount then + result.StopFurtherProcessing () + next.ProcessNext input + else + result.StopFurtherProcessing () + false + module Enumerable = [] type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ISeqComponent) = @@ -1711,12 +1720,7 @@ namespace Microsoft.FSharp.Collections [] let truncate n (source: seq<'T>) = - checkNonNull "source" source - seq { let i = ref 0 - use ie = source.GetEnumerator() - while !i < n && ie.MoveNext() do - i := !i + 1 - yield ie.Current } + source |> seqFactory (SeqComposer.TruncateFactory n) [] let pairwise<'T> (source:seq<'T>) : seq<'T*'T> = From f0f74e41693eb55f9cf5202cc4154f01551e1767 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Wed, 12 Oct 2016 10:08:05 +0200 Subject: [PATCH 07/59] Carry on disposing under exceptions bug fix: "truncate 0" was causing MoveNext on underlying seq --- src/fsharp/FSharp.Core/seq.fs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 9336b1bfd7f..e8792358d98 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -805,8 +805,10 @@ namespace Microsoft.FSharp.Collections interface ISeqComponent with override __.OnDispose () = - input2.Dispose () - (Helpers.UpcastISeqComponent next).OnDispose () + try + input2.Dispose () + finally + (Helpers.UpcastISeqComponent next).OnDispose () and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:Result<'V>, next:SeqComponent<'U,'V>) = inherit SeqComponent<'Second,'V>(next) @@ -823,8 +825,10 @@ namespace Microsoft.FSharp.Collections interface ISeqComponent with override __.OnDispose () = - input1.Dispose () - (Helpers.UpcastISeqComponent next).OnDispose () + try + input1.Dispose () + finally + (Helpers.UpcastISeqComponent next).OnDispose () and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqComponent<'U,'V>) = inherit SeqComponent<'T,'V>(next) @@ -1007,8 +1011,10 @@ namespace Microsoft.FSharp.Collections interface IDisposable with member __.Dispose() = - source.Dispose () - (Helpers.UpcastISeqComponent seqComponent).OnDispose () + try + source.Dispose () + finally + (Helpers.UpcastISeqComponent seqComponent).OnDispose () and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqComponentFactory<'T,'U>) = inherit EnumerableBase<'U>() @@ -1720,6 +1726,7 @@ namespace Microsoft.FSharp.Collections [] let truncate n (source: seq<'T>) = + if n <= 0 then empty else source |> seqFactory (SeqComposer.TruncateFactory n) [] From 701fc830699efcb27cf729722f08e425db7eda6a Mon Sep 17 00:00:00 2001 From: liboz Date: Thu, 13 Oct 2016 03:46:26 +0200 Subject: [PATCH 08/59] distinct/distinctby except indexed --- src/fsharp/FSharp.Core/seq.fs | 72 ++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index e8792358d98..26ff381d641 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -690,6 +690,18 @@ namespace Microsoft.FSharp.Collections and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Choose (filter, next) + + and DistinctFactory<'T when 'T: equality> () = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Distinct (next) + + and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast DistinctBy (keyFunction, next) + + and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Except (itemsToExclude, next) and FilterFactory<'T> (filter:'T->bool) = inherit SeqComponentFactory<'T,'T> () @@ -762,6 +774,39 @@ namespace Microsoft.FSharp.Collections | Some value -> Helpers.avoidTailCall (next.ProcessNext value) | None -> false + and Distinct<'T,'V when 'T: equality> (next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) + + override __.ProcessNext (input:'T) : bool = + if hashSet.Add input then + Helpers.avoidTailCall (next.ProcessNext input) + else + false + + and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) + + override __.ProcessNext (input:'T) : bool = + if hashSet.Add(keyFunction input) then + Helpers.avoidTailCall (next.ProcessNext input) + else + false + + and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) + + override __.ProcessNext (input:'T) : bool = + if cached.Value.Add input then + Helpers.avoidTailCall (next.ProcessNext input) + else + false + and Filter<'T,'V> (filter:'T->bool, next:SeqComponent<'T,'V>) = inherit SeqComponent<'T,'V>(next) @@ -1493,8 +1538,7 @@ namespace Microsoft.FSharp.Collections [] let indexed source = - checkNonNull "source" source - mapi (fun i x -> i,x) source + source |> seqFactory (SeqComposer.MapiFactory (fun i x -> i,x) ) [] let zip source1 source2 = @@ -1939,19 +1983,11 @@ namespace Microsoft.FSharp.Collections [] let distinct source = - checkNonNull "source" source - seq { let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) - for v in source do - if hashSet.Add(v) then - yield v } + source |> seqFactory (SeqComposer.DistinctFactory ()) [] let distinctBy keyf source = - checkNonNull "source" source - seq { let hashSet = HashSet<_>(HashIdentity.Structural<_>) - for v in source do - if hashSet.Add(keyf v) then - yield v } + source |> seqFactory (SeqComposer.DistinctByFactory keyf) [] let sortBy keyf source = @@ -2284,17 +2320,7 @@ namespace Microsoft.FSharp.Collections [] let except (itemsToExclude: seq<'T>) (source: seq<'T>) = checkNonNull "itemsToExclude" itemsToExclude - checkNonNull "source" source - - seq { - use e = source.GetEnumerator() - if e.MoveNext() then - let cached = HashSet(itemsToExclude, HashIdentity.Structural) - let next = e.Current - if (cached.Add next) then yield next - while e.MoveNext() do - let next = e.Current - if (cached.Add next) then yield next } + source |> seqFactory (SeqComposer.ExceptFactory itemsToExclude) [] let chunkBySize chunkSize (source : seq<_>) = From d7c26d1cd04726d4464a6448ac5553ace8f15c84 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Mon, 10 Oct 2016 19:35:48 +1100 Subject: [PATCH 09/59] Seq.append This implemention performs vastly better than the previous implementation, which appeared to be more interested in being theoretically important than actually being a reasonable implementation. Anyway, the previous version blew up with stack overflow if you appended too many things, which the new version doesn't. --- src/fsharp/FSharp.Core/seq.fs | 44 ++++++----------------------------- 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 26ff381d641..85bf3f897a1 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -981,23 +981,6 @@ namespace Microsoft.FSharp.Collections result.Current <- input true - and Truncate<'T,'V> (truncateCount:int, result:Result<'V>, next:SeqComponent<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable count = 0 - - member __.Count = count - - override __.ProcessNext (input:'T) : bool = - if count < truncateCount then - count <- count + 1 - if count = truncateCount then - result.StopFurtherProcessing () - next.ProcessNext input - else - result.StopFurtherProcessing () - false - module Enumerable = [] type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ISeqComponent) = @@ -1022,7 +1005,6 @@ namespace Microsoft.FSharp.Collections and [] EnumerableBase<'T> () = abstract member Compose<'U> : (SeqComponentFactory<'T,'U>) -> IEnumerable<'U> abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> - abstract member Fold<'State> : folder:('State->'T->'State) -> state:'State -> 'State default this.Append source = Helpers.UpcastEnumerable (AppendEnumerable [this; source]) @@ -1108,15 +1090,13 @@ namespace Microsoft.FSharp.Collections interface IEnumerator<'T> with member __.Current = - if state = SeqProcessNextStates.InProcess then active.Current - else - match state with - | SeqProcessNextStates.NotStarted -> notStarted() - | SeqProcessNextStates.Finished -> alreadyFinished() - | _ -> failwith "library implementation error: all states should have been handled" + match state with + | SeqProcessNextStates.NotStarted -> notStarted() + | SeqProcessNextStates.Finished -> alreadyFinished() + | _ -> active.Current interface IEnumerator with - member this.Current = box ((Helpers.UpcastEnumerator this)).Current + member __.Current = (Helpers.UpcastEnumeratorNonGeneric active).Current member __.MoveNext () = state <- SeqProcessNextStates.InProcess moveNext () @@ -1139,18 +1119,6 @@ namespace Microsoft.FSharp.Collections override this.Append source = Helpers.UpcastEnumerable (AppendEnumerable (source :: sources)) - override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - - let enumerable = Helpers.UpcastEnumerable (AppendEnumerable sources) - let enumerator = enumerable.GetEnumerator () - - let mutable state = initialState - while enumerator.MoveNext () do - state <- folder'.Invoke (state, enumerator.Current) - - state - module Array = type Enumerator<'T,'U>(array:array<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) @@ -1264,6 +1232,8 @@ namespace Microsoft.FSharp.Collections // so you already know what the count is!! Anyway, someone thought it was a good idea, so // I have had to add an extra function that is used in Skip to determine if we are touching // Current or not. + type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:SeqComponent<'T,'U>, signal:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) let getTerminatingIdx (count:Nullable) = // we are offset by 1 to allow for values going up to System.Int32.MaxValue From e0d78fdf2ce3ad6b9ef68733cdb07e095e12cbdc Mon Sep 17 00:00:00 2001 From: liboz Date: Fri, 14 Oct 2016 04:53:06 +0200 Subject: [PATCH 10/59] zip/zip3 Removed old choose function localizing upto This is retained for compatibility cleaning up SeqComposer.Helpers - better comments - consistent casing Seq.map3 Seq.mapi2 Simplified map2 - removing the check of both types Seq.unfold Added an IdentityFactory Identity can be used to wrap basic containers into SeqComposer compatible types, but can safely be removed when composing the components. --- src/fsharp/FSharp.Core/seq.fs | 455 +++++++++++++++++----------------- 1 file changed, 222 insertions(+), 233 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 85bf3f897a1..67966c3b780 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -70,169 +70,6 @@ namespace Microsoft.FSharp.Collections if index = 0 then e.Current else nth (index-1) e - [] - type MapEnumeratorState = - | NotStarted - | InProcess - | Finished - - [] - type MapEnumerator<'T> () = - let mutable state = NotStarted - [] - val mutable private curr : 'T - - member this.GetCurrent () = - match state with - | NotStarted -> notStarted() - | Finished -> alreadyFinished() - | InProcess -> () - this.curr - - abstract DoMoveNext : byref<'T> -> bool - abstract Dispose : unit -> unit - - interface IEnumerator<'T> with - member this.Current = this.GetCurrent() - - interface IEnumerator with - member this.Current = box(this.GetCurrent()) - member this.MoveNext () = - state <- InProcess - if this.DoMoveNext(&this.curr) then - true - else - state <- Finished - false - member this.Reset() = noReset() - interface System.IDisposable with - member this.Dispose() = this.Dispose() - - let mapi2 f (e1 : IEnumerator<_>) (e2 : IEnumerator<_>) : IEnumerator<_> = - let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f) - let i = ref (-1) - upcast - { new MapEnumerator<_>() with - member this.DoMoveNext curr = - i := !i + 1 - if (e1.MoveNext() && e2.MoveNext()) then - curr <- f.Invoke(!i, e1.Current, e2.Current) - true - else - false - member this.Dispose() = - try - e1.Dispose() - finally - e2.Dispose() - } - - let map3 f (e1 : IEnumerator<_>) (e2 : IEnumerator<_>) (e3 : IEnumerator<_>) : IEnumerator<_> = - let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f) - upcast - { new MapEnumerator<_>() with - member this.DoMoveNext curr = - let n1 = e1.MoveNext() - let n2 = e2.MoveNext() - let n3 = e3.MoveNext() - - if n1 && n2 && n3 then - curr <- f.Invoke(e1.Current, e2.Current, e3.Current) - true - else - false - member this.Dispose() = - try - e1.Dispose() - finally - try - e2.Dispose() - finally - e3.Dispose() - } - - let choose f (e : IEnumerator<'T>) = - let started = ref false - let curr = ref None - let get() = check !started; (match !curr with None -> alreadyFinished() | Some x -> x) - { new IEnumerator<'U> with - member x.Current = get() - interface IEnumerator with - member x.Current = box (get()) - member x.MoveNext() = - if not !started then started := true - curr := None - while ((!curr).IsNone && e.MoveNext()) do - curr := f e.Current - Option.isSome !curr - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = e.Dispose() } - - let unfold f x : IEnumerator<_> = - let state = ref x - upcast - { new MapEnumerator<_>() with - member this.DoMoveNext curr = - match f !state with - | None -> false - | Some(r,s) -> - curr <- r - state := s - true - member this.Dispose() = () - } - - let upto lastOption f = - match lastOption with - | Some b when b<0 -> Empty() // a request for -ve length returns empty sequence - | _ -> - let unstarted = -1 // index value means unstarted (and no valid index) - let completed = -2 // index value means completed (and no valid index) - let unreachable = -3 // index is unreachable from 0,1,2,3,... - let finalIndex = match lastOption with - | Some b -> b // here b>=0, a valid end value. - | None -> unreachable // run "forever", well as far as Int32.MaxValue since indexing with a bounded type. - // The Current value for a valid index is "f i". - // Lazy<_> values are used as caches, to store either the result or an exception if thrown. - // These "Lazy<_>" caches are created only on the first call to current and forced immediately. - // The lazy creation of the cache nodes means enumerations that skip many Current values are not delayed by GC. - // For example, the full enumeration of Seq.initInfinite in the tests. - // state - let index = ref unstarted - // a Lazy node to cache the result/exception - let current = ref (Unchecked.defaultof<_>) - let setIndex i = index := i; current := (Unchecked.defaultof<_>) // cache node unprimed, initialised on demand. - let getCurrent() = - if !index = unstarted then notStarted() - if !index = completed then alreadyFinished() - match box !current with - | null -> current := Lazy<_>.Create(fun () -> f !index) - | _ -> () - // forced or re-forced immediately. - (!current).Force() - { new IEnumerator<'U> with - member x.Current = getCurrent() - interface IEnumerator with - member x.Current = box (getCurrent()) - member x.MoveNext() = - if !index = completed then - false - elif !index = unstarted then - setIndex 0 - true - else ( - if !index = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) - if !index = finalIndex then - false - else - setIndex (!index + 1) - true - ) - member self.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = () } - let readAndClear r = lock r (fun () -> match !r with None -> None | Some _ as res -> r := None; res) @@ -648,17 +485,16 @@ namespace Microsoft.FSharp.Collections module Helpers = // used for performance reasons; these are not recursive calls, so should be safe - let inline avoidTailCall x = - match x with - | true -> true - | false -> false - - let inline ComposeFilter f g x = f x && g x + // ** it should be noted that potential changes to the f# compiler may render this function + // ineffictive ** + let inline avoidTailCall boolean = match boolean with true -> true | false -> false - let inline UpcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) - let inline UpcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) - let inline UpcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) - let inline UpcastISeqComponent (t:#ISeqComponent) : ISeqComponent = (# "" t : ISeqComponent #) + // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality + // is fixed with the compiler then these functions can be removed. + let inline upcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) + let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) + let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) + let inline upcastISeqComponent (t:#ISeqComponent) : ISeqComponent = (# "" t : ISeqComponent #) type SeqProcessNextStates = | InProcess = 0 @@ -682,11 +518,24 @@ namespace Microsoft.FSharp.Collections type [] SeqComponentFactory<'T,'U> () = abstract Create<'V> : Result<'V> -> SeqComponent<'U,'V> -> SeqComponent<'T,'V> + abstract IsIdentity : bool - and ComposedFactory<'T,'U,'V> (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>) = + default __.IsIdentity = false + + and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>) = inherit SeqComponentFactory<'T,'V> () override __.Create<'W> (result:Result<'W>) (next:SeqComponent<'V,'W>) : SeqComponent<'T,'W> = first.Create result (second.Create result next) + static member Combine (first:SeqComponentFactory<'T,'U>) (second:SeqComponentFactory<'U,'V>) : SeqComponentFactory<'T,'V> = + let castToTV (factory:obj) = + match factory with + | :? SeqComponentFactory<'T,'V> as result -> result + | _ -> failwith "library implementation error: they types must match when paired with identity" + + if first.IsIdentity then castToTV second + elif second.IsIdentity then castToTV first + else upcast ComposedFactory(first, second) + and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Choose (filter, next) @@ -707,22 +556,31 @@ namespace Microsoft.FSharp.Collections inherit SeqComponentFactory<'T,'T> () override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = next.CreateFilter filter + and IdentityFactory<'T> () = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = next.CreateMap id + override __.IsIdentity = true + and MapFactory<'T,'U> (map:'T->'U) = inherit SeqComponentFactory<'T,'U> () override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = next.CreateMap map - and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = + and Map2Factory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map2First (map, input2, result, next) + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map2 (map, input2, result, next) - and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = - inherit SeqComponentFactory<'Second,'U> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'Second,'V> = upcast Map2Second (map, input1, result, next) + and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = + inherit SeqComponentFactory<'First,'U> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map3 (map, input2, input3, result, next) and MapiFactory<'T,'U> (mapi:int->'T->'U) = inherit SeqComponentFactory<'T,'U> () override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Mapi (mapi, next) + and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = + inherit SeqComponentFactory<'First,'U> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Mapi2 (map, input2, result, next) + and PairwiseFactory<'T> () = inherit SeqComponentFactory<'T,'T*'T> () override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T*'T,'V>) : SeqComponent<'T,'V> = upcast Pairwise next @@ -835,7 +693,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = Helpers.avoidTailCall (next.ProcessNext (map input)) - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = + and Map2<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () @@ -853,17 +711,18 @@ namespace Microsoft.FSharp.Collections try input2.Dispose () finally - (Helpers.UpcastISeqComponent next).OnDispose () + (Helpers.upcastISeqComponent next).OnDispose () - and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:Result<'V>, next:SeqComponent<'U,'V>) = - inherit SeqComponent<'Second,'V>(next) + and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:Result<'V>, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'First,'V>(next) - let input1 = enumerable1.GetEnumerator () - let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map + let input2 = enumerable2.GetEnumerator () + let input3 = enumerable3.GetEnumerator () + let map' = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt map - override __.ProcessNext (input:'Second) : bool = - if input1.MoveNext () then - Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) + override __.ProcessNext (input:'First) : bool = + if input2.MoveNext () && input3.MoveNext () then + Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) else result.StopFurtherProcessing () false @@ -871,9 +730,12 @@ namespace Microsoft.FSharp.Collections interface ISeqComponent with override __.OnDispose () = try - input1.Dispose () + input2.Dispose () finally - (Helpers.UpcastISeqComponent next).OnDispose () + try + input3.Dispose () + finally + (Helpers.upcastISeqComponent next).OnDispose () and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqComponent<'U,'V>) = inherit SeqComponent<'T,'V>(next) @@ -895,6 +757,28 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) + and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'First,'V>(next) + + let mutable idx = 0 + let input2 = enumerable2.GetEnumerator () + let mapi2' = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt map + + override __.ProcessNext (input:'First) : bool = + if input2.MoveNext () then + idx <- idx + 1 + Helpers.avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) + else + result.StopFurtherProcessing () + false + + interface ISeqComponent with + override __.OnDispose () = + try + input2.Dispose () + finally + (Helpers.upcastISeqComponent next).OnDispose () + and Pairwise<'T,'V> (next:SeqComponent<'T*'T,'V>) = inherit SeqComponent<'T,'V>(next) @@ -936,7 +820,7 @@ namespace Microsoft.FSharp.Collections let x = skipCount - count invalidOpFmt "tried to skip {0} {1} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - (Helpers.UpcastISeqComponent next).OnComplete () + (Helpers.upcastISeqComponent next).OnComplete () and SkipWhile<'T,'V> (predicate:'T->bool, next:SeqComponent<'T,'V>) = inherit SeqComponent<'T,'V>(next) @@ -962,7 +846,7 @@ namespace Microsoft.FSharp.Collections let x = takeCount - this.Count invalidOpFmt "tried to take {0} {1} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - (Helpers.UpcastISeqComponent next).OnComplete () + (Helpers.upcastISeqComponent next).OnComplete () and TakeWhile<'T,'V> (predicate:'T->bool, result:Result<'V>, next:SeqComponent<'T,'V>) = inherit SeqComponent<'T,'V>(next) @@ -989,7 +873,7 @@ namespace Microsoft.FSharp.Collections seqComponent.OnDispose () interface IEnumerator with - member this.Current : obj = box ((Helpers.UpcastEnumerator this)).Current + member this.Current : obj = box ((Helpers.upcastEnumerator this)).Current member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)" member __.Reset () : unit = noReset () @@ -1006,13 +890,13 @@ namespace Microsoft.FSharp.Collections abstract member Compose<'U> : (SeqComponentFactory<'T,'U>) -> IEnumerable<'U> abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> - default this.Append source = Helpers.UpcastEnumerable (AppendEnumerable [this; source]) + default this.Append source = Helpers.upcastEnumerable (AppendEnumerable [this; source]) interface IEnumerable with member this.GetEnumerator () : IEnumerator = - let genericEnumerable = Helpers.UpcastEnumerable this + let genericEnumerable = Helpers.upcastEnumerable this let genericEnumerator = genericEnumerable.GetEnumerator () - Helpers.UpcastEnumeratorNonGeneric genericEnumerator + Helpers.upcastEnumeratorNonGeneric genericEnumerator interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = failwith "library implementation error: derived class should implement (should be abstract)" @@ -1028,7 +912,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.UpcastISeqComponent seqComponent).OnComplete () + (Helpers.upcastISeqComponent seqComponent).OnComplete () false interface IEnumerator with @@ -1041,7 +925,7 @@ namespace Microsoft.FSharp.Collections try source.Dispose () finally - (Helpers.UpcastISeqComponent seqComponent).OnDispose () + (Helpers.upcastISeqComponent seqComponent).OnDispose () and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqComponentFactory<'T,'U>) = inherit EnumerableBase<'U>() @@ -1049,10 +933,10 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.UpcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (Tail result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.UpcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory (current, next))) + Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder @@ -1096,7 +980,7 @@ namespace Microsoft.FSharp.Collections | _ -> active.Current interface IEnumerator with - member __.Current = (Helpers.UpcastEnumeratorNonGeneric active).Current + member this.Current = box ((Helpers.upcastEnumerator this)).Current member __.MoveNext () = state <- SeqProcessNextStates.InProcess moveNext () @@ -1111,13 +995,25 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = - Helpers.UpcastEnumerator (new AppendEnumerator<_> (sources)) + Helpers.upcastEnumerator (new AppendEnumerator<_> (sources)) override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = - Helpers.UpcastEnumerable (Enumerable<'T,'V>(this, next)) + Helpers.upcastEnumerable (Enumerable<'T,'V>(this, next)) override this.Append source = - Helpers.UpcastEnumerable (AppendEnumerable (source :: sources)) + Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) + + override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) + let enumerator = enumerable.GetEnumerator () + + let mutable state = initialState + while enumerator.MoveNext () do + state <- folder'.Invoke (state, enumerator.Current) + + state module Array = type Enumerator<'T,'U>(array:array<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = @@ -1134,7 +1030,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.UpcastISeqComponent seqComponent).OnComplete () + (Helpers.upcastISeqComponent seqComponent).OnComplete () false interface IEnumerator with @@ -1148,10 +1044,10 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.UpcastEnumerator (new Enumerator<'T,'U>(array, current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(array, current.Create result (Tail result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.UpcastEnumerable (new Enumerable<'T,'V>(array, ComposedFactory (current, next))) + Helpers.upcastEnumerable (new Enumerable<'T,'V>(array, ComposedFactory.Combine current next)) override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder @@ -1184,7 +1080,7 @@ namespace Microsoft.FSharp.Collections moveNext tail | _ -> result.SeqState <- SeqProcessNextStates.Finished - (Helpers.UpcastISeqComponent seqComponent).OnComplete () + (Helpers.upcastISeqComponent seqComponent).OnComplete () false interface IEnumerator with @@ -1198,10 +1094,10 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.UpcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (Tail result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.UpcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory (current, next))) + Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder @@ -1221,6 +1117,56 @@ namespace Microsoft.FSharp.Collections fold initialState alist + module Unfold = + type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:SeqComponent<'T,'U>, signal:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) + + let mutable current = state + + let rec moveNext () = + match generator current with + | None -> false + | Some (item, nextState) -> + current <- nextState + if seqComponent.ProcessNext item then + true + else + moveNext () + + interface IEnumerator with + member __.MoveNext () = + signal.SeqState <- SeqProcessNextStates.InProcess + moveNext () + + type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqComponentFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (Tail result), result)) + + override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = + Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let result = Result<'U> () + let components = current.Create result (Tail result) + + let rec fold state current = + match result.Halted, generator current with + | true, _ + | false, None -> state + | false, Some (item, next) -> + if components.ProcessNext item then + fold (folder'.Invoke (state, result.Current)) next + else + fold state next + + fold initialState state + module Init = // The original implementation of "init" delayed the calculation of Current, and so it was possible // to do MoveNext without it's value being calculated. @@ -1271,7 +1217,7 @@ namespace Microsoft.FSharp.Collections raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) else signal.SeqState <- SeqProcessNextStates.Finished - (Helpers.UpcastISeqComponent seqComponent).OnComplete () + (Helpers.upcastISeqComponent seqComponent).OnComplete () false interface IEnumerator with @@ -1285,10 +1231,10 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.UpcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (Tail result), result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.UpcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory (current, next))) + Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder @@ -1313,6 +1259,56 @@ namespace Microsoft.FSharp.Collections state + let upto lastOption f = + match lastOption with + | Some b when b<0 -> failwith "library implementation error: upto can never be called with a negative value" + | _ -> + let unstarted = -1 // index value means unstarted (and no valid index) + let completed = -2 // index value means completed (and no valid index) + let unreachable = -3 // index is unreachable from 0,1,2,3,... + let finalIndex = match lastOption with + | Some b -> b // here b>=0, a valid end value. + | None -> unreachable // run "forever", well as far as Int32.MaxValue since indexing with a bounded type. + // The Current value for a valid index is "f i". + // Lazy<_> values are used as caches, to store either the result or an exception if thrown. + // These "Lazy<_>" caches are created only on the first call to current and forced immediately. + // The lazy creation of the cache nodes means enumerations that skip many Current values are not delayed by GC. + // For example, the full enumeration of Seq.initInfinite in the tests. + // state + let index = ref unstarted + // a Lazy node to cache the result/exception + let current = ref (Unchecked.defaultof<_>) + let setIndex i = index := i; current := (Unchecked.defaultof<_>) // cache node unprimed, initialised on demand. + let getCurrent() = + if !index = unstarted then notStarted() + if !index = completed then alreadyFinished() + match box !current with + | null -> current := Lazy<_>.Create(fun () -> f !index) + | _ -> () + // forced or re-forced immediately. + (!current).Force() + { new IEnumerator<'U> with + member x.Current = getCurrent() + interface IEnumerator with + member x.Current = box (getCurrent()) + member x.MoveNext() = + if !index = completed then + false + elif !index = unstarted then + setIndex 0 + true + else ( + if !index = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) + if !index = finalIndex then + false + else + setIndex (!index + 1) + true + ) + member self.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = () } + type EnumerableDecider<'T>(count:Nullable, f:int->'T) = inherit Enumerable.EnumerableBase<'T>() @@ -1324,12 +1320,12 @@ namespace Microsoft.FSharp.Collections upto (if count.HasValue then Some (count.Value-1) else None) f override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = - Helpers.UpcastEnumerable (Enumerable<'T,'V>(count, f, next)) + Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - let enumerator = (Helpers.UpcastEnumerable this).GetEnumerator () + let enumerator = (Helpers.upcastEnumerable this).GetEnumerator () let mutable state = initialState while enumerator.MoveNext () do @@ -1345,27 +1341,27 @@ namespace Microsoft.FSharp.Collections open Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers let mkDelayedSeq (f: unit -> IEnumerable<'T>) = mkSeq (fun () -> f().GetEnumerator()) - let mkUnfoldSeq f x = mkSeq (fun () -> IEnumerator.unfold f x) let inline indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) [] let delay f = mkDelayedSeq f [] - let unfold f x = mkUnfoldSeq f x + let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> = + SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Unfold.Enumerable<'T,'T,'State>(generator, state, SeqComposer.IdentityFactory ())) [] let empty<'T> = (EmptyEnumerable :> seq<'T>) [] let initInfinite<'T> (f:int->'T) : IEnumerable<'T> = - SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.Init.EnumerableDecider<'T>(Nullable (), f)) + SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Init.EnumerableDecider<'T>(Nullable (), f)) [] let init<'T> (count:int) (f:int->'T) : IEnumerable<'T> = if count < 0 then invalidArgInputMustBeNonNegative "count" count elif count = 0 then empty else - SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.Init.EnumerableDecider<'T>(Nullable count, f)) + SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Init.EnumerableDecider<'T>(Nullable count, f)) [] let iter f (source : seq<'T>) = @@ -1462,9 +1458,9 @@ namespace Microsoft.FSharp.Collections checkNonNull "source" source match source with | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Compose createSeqComponent - | :? array<'T> as a -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.Array.Enumerable<_,_>(a, createSeqComponent)) - | :? list<'T> as a -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.List.Enumerable<_,_>(a, createSeqComponent)) - | _ -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.Enumerable.Enumerable<_,_>(source, createSeqComponent)) + | :? array<'T> as a -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Array.Enumerable<_,_>(a, createSeqComponent)) + | :? list<'T> as a -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.List.Enumerable<_,_>(a, createSeqComponent)) + | _ -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Enumerable.Enumerable<_,_>(source, createSeqComponent)) [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = @@ -1485,22 +1481,20 @@ namespace Microsoft.FSharp.Collections let mapi2 f source1 source2 = checkNonNull "source1" source1 checkNonNull "source2" source2 - revamp2 (IEnumerator.mapi2 f) source1 source2 + source1 |> seqFactory (SeqComposer.Mapi2Factory (f, source2)) [] let map2<'T,'U,'V> (f:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = checkNonNull "source1" source1 checkNonNull "source2" source2 - match source1 with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Compose (SeqComposer.Map2FirstFactory (f, source2)) - | _ -> source2 |> seqFactory (SeqComposer.Map2SecondFactory (f, source1)) + source1 |> seqFactory (SeqComposer.Map2Factory (f, source2)) [] let map3 f source1 source2 source3 = checkNonNull "source1" source1 checkNonNull "source2" source2 checkNonNull "source3" source3 - revamp3 (IEnumerator.map3 f) source1 source2 source3 + source1 |> seqFactory (SeqComposer.Map3Factory (f, source2, source3)) [] let choose f source = @@ -1512,15 +1506,10 @@ namespace Microsoft.FSharp.Collections [] let zip source1 source2 = - checkNonNull "source1" source1 - checkNonNull "source2" source2 map2 (fun x y -> x,y) source1 source2 [] let zip3 source1 source2 source3 = - checkNonNull "source1" source1 - checkNonNull "source2" source2 - checkNonNull "source3" source3 map2 (fun x (y,z) -> x,y,z) source1 (zip source2 source3) [] @@ -1649,7 +1638,7 @@ namespace Microsoft.FSharp.Collections checkNonNull "source2" source2 match source1 with | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Append source2 - | _ -> SeqComposer.Helpers.UpcastEnumerable (new SeqComposer.Enumerable.AppendEnumerable<_>([source2; source1])) + | _ -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Enumerable.AppendEnumerable<_>([source2; source1])) [] From 82aa192621dbce4393355dd327eb659e0d81614d Mon Sep 17 00:00:00 2001 From: liboz Date: Sat, 15 Oct 2016 02:13:25 +0200 Subject: [PATCH 11/59] Made map2 more complex (reverted from commit ceaed6cd7cb9f842fb9b47440bff7cedeed74629) Also removed some extra null checks fixed to removing the right null check seq.tail and a fix to takewhile to use avoidtailcall --- src/fsharp/FSharp.Core/seq.fs | 105 ++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 24 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 67966c3b780..b00bf073567 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -565,9 +565,13 @@ namespace Microsoft.FSharp.Collections inherit SeqComponentFactory<'T,'U> () override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = next.CreateMap map - and Map2Factory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = + and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map2 (map, input2, result, next) + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map2First (map, input2, result, next) + + and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = + inherit SeqComponentFactory<'Second,'U> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'Second,'V> = upcast Map2Second (map, input1, result, next) and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = inherit SeqComponentFactory<'First,'U> () @@ -601,6 +605,10 @@ namespace Microsoft.FSharp.Collections inherit SeqComponentFactory<'T,'T> () override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Take (count, result, next) + and TailFactory<'T> () = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Tail<'T,'V> (next) + and TruncateFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Truncate (count, result, next) @@ -693,7 +701,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = Helpers.avoidTailCall (next.ProcessNext (map input)) - and Map2<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = + and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () @@ -713,6 +721,26 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () + and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:Result<'V>, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'Second,'V>(next) + + let input1 = enumerable1.GetEnumerator () + let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map + + override __.ProcessNext (input:'Second) : bool = + if input1.MoveNext () then + Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) + else + result.StopFurtherProcessing () + false + + interface ISeqComponent with + override __.OnDispose () = + try + input1.Dispose () + finally + (Helpers.upcastISeqComponent next).OnDispose () + and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:Result<'V>, next:SeqComponent<'U,'V>) = inherit SeqComponent<'First,'V>(next) @@ -853,7 +881,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if predicate input then - next.ProcessNext input + Helpers.avoidTailCall (next.ProcessNext input) else result.StopFurtherProcessing () false @@ -865,6 +893,41 @@ namespace Microsoft.FSharp.Collections result.Current <- input true + and Tail<'T, 'V> (next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable first = true + + override __.ProcessNext (input:'T) : bool = + if first then + first <- false + false + else + Helpers.avoidTailCall (next.ProcessNext input) + + interface ISeqComponent with + override this.OnComplete () = + if first then + invalidArg "source" (SR.GetString(SR.notEnoughElements)) + (Helpers.upcastISeqComponent next).OnComplete () + + and Truncate<'T,'V> (truncateCount:int, result:Result<'V>, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable count = 0 + + member __.Count = count + + override __.ProcessNext (input:'T) : bool = + if count < truncateCount then + count <- count + 1 + if count = truncateCount then + result.StopFurtherProcessing () + next.ProcessNext input + else + result.StopFurtherProcessing () + false + module Enumerable = [] type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ISeqComponent) = @@ -933,7 +996,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (Tail<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) @@ -944,7 +1007,7 @@ namespace Microsoft.FSharp.Collections let enumerator = enumerable.GetEnumerator () let result = Result<'U> () - let components = current.Create result (Tail result) + let components = current.Create result (Tail<'U> result) let mutable state = initialState while (not result.Halted) && (enumerator.MoveNext ()) do @@ -1044,7 +1107,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(array, current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(array, current.Create result (Tail<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(array, ComposedFactory.Combine current next)) @@ -1054,7 +1117,7 @@ namespace Microsoft.FSharp.Collections let mutable idx = 0 let result = Result<'U> () - let components = current.Create result (Tail result) + let components = current.Create result (Tail<'U> result) let mutable state = initialState while (not result.Halted) && (idx < array.Length) do @@ -1094,7 +1157,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (Tail<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) @@ -1103,7 +1166,7 @@ namespace Microsoft.FSharp.Collections let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let result = Result<'U> () - let components = current.Create result (Tail result) + let components = current.Create result (Tail<'U> result) let rec fold state lst = match result.Halted, lst with @@ -1144,7 +1207,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (Tail<'U> result), result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) @@ -1153,7 +1216,7 @@ namespace Microsoft.FSharp.Collections let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let result = Result<'U> () - let components = current.Create result (Tail result) + let components = current.Create result (Tail<'U> result) let rec fold state current = match result.Halted, generator current with @@ -1231,7 +1294,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (Tail<'U> result), result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) @@ -1240,7 +1303,7 @@ namespace Microsoft.FSharp.Collections let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let result = Result<'U> () - let components = current.Create result (Tail result) + let components = current.Create result (Tail<'U> result) let mutable idx = -1 let terminatingIdx = getTerminatingIdx count @@ -1479,19 +1542,18 @@ namespace Microsoft.FSharp.Collections [] let mapi2 f source1 source2 = - checkNonNull "source1" source1 checkNonNull "source2" source2 source1 |> seqFactory (SeqComposer.Mapi2Factory (f, source2)) [] let map2<'T,'U,'V> (f:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = checkNonNull "source1" source1 - checkNonNull "source2" source2 - source1 |> seqFactory (SeqComposer.Map2Factory (f, source2)) + match source1 with + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Compose (SeqComposer.Map2FirstFactory (f, source2)) + | _ -> source2 |> seqFactory (SeqComposer.Map2SecondFactory (f, source1)) [] let map3 f source1 source2 source3 = - checkNonNull "source1" source1 checkNonNull "source2" source2 checkNonNull "source3" source3 source1 |> seqFactory (SeqComposer.Map3Factory (f, source2, source3)) @@ -2207,12 +2269,7 @@ namespace Microsoft.FSharp.Collections [] let tail (source: seq<'T>) = - checkNonNull "source" source - seq { use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" (SR.GetString(SR.notEnoughElements)) - while e.MoveNext() do - yield e.Current } + source |> seqFactory (SeqComposer.TailFactory ()) [] let last (source : seq<_>) = From 459d3dbdfce01ca65959c9564c8f44b6fcdad5ec Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sat, 15 Oct 2016 07:57:55 +0200 Subject: [PATCH 12/59] Seq.ofArray Seq.rev Added brackets to disambiguate Lazy Seq.permute Seq.sort(By|With|ByDescending|Descending)? Factory helper create methods for less clutter Replaced Lazy<'T> with (unit->'T) The use of lazy changed the seq's funcitonality, as it would have only been calculated once, even if the sequence was iterated again. Renamed Tail to SetResult to disambiguate Added Iter Seq.iter & Seq.average --- src/fsharp/FSharp.Core/seq.fs | 243 ++++++++++++++++++++++++---------- 1 file changed, 172 insertions(+), 71 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index b00bf073567..490d1fe808f 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -101,31 +101,6 @@ namespace Microsoft.FSharp.Collections interface System.IDisposable with member x.Dispose() = dispose() } - [] - type ArrayEnumerator<'T>(arr: 'T array) = - let mutable curr = -1 - let mutable len = arr.Length - member x.Get() = - if curr >= 0 then - if curr >= len then alreadyFinished() - else arr.[curr] - else - notStarted() - interface IEnumerator<'T> with - member x.Current = x.Get() - interface System.Collections.IEnumerator with - member x.MoveNext() = - if curr >= len then false - else - curr <- curr + 1 - (curr < len) - member x.Current = box(x.Get()) - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = () - - let ofArray arr = (new ArrayEnumerator<'T>(arr) :> IEnumerator<'T>) - [] type Singleton<'T>(v:'T) = let mutable started = false @@ -886,13 +861,6 @@ namespace Microsoft.FSharp.Collections result.StopFurtherProcessing () false - and Tail<'T> (result:Result<'T>) = - inherit SeqComponent<'T,'T>(seqComponentTail) - - override __.ProcessNext (input:'T) : bool = - result.Current <- input - true - and Tail<'T, 'V> (next:SeqComponent<'T,'V>) = inherit SeqComponent<'T,'V>(next) @@ -928,6 +896,14 @@ namespace Microsoft.FSharp.Collections result.StopFurtherProcessing () false + // SetResult<> is used at the end of the chain of SeqComponents to assign the final value + type SetResult<'T> (result:Result<'T>) = + inherit SeqComponent<'T,'T>(seqComponentTail) + + override __.ProcessNext (input:'T) : bool = + result.Current <- input + true + module Enumerable = [] type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ISeqComponent) = @@ -950,8 +926,9 @@ namespace Microsoft.FSharp.Collections | _ -> failwith "library implementation error: all states should have been handled" and [] EnumerableBase<'T> () = - abstract member Compose<'U> : (SeqComponentFactory<'T,'U>) -> IEnumerable<'U> - abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> + abstract member Compose<'U> : (SeqComponentFactory<'T,'U>) -> IEnumerable<'U> + abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> + abstract member Iter : f:('T->unit) -> unit default this.Append source = Helpers.upcastEnumerable (AppendEnumerable [this; source]) @@ -996,18 +973,28 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (Tail<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (SetResult<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) + override this.Iter (f:'U->unit) : unit = + let enumerator = enumerable.GetEnumerator () + let result = Result<'U> () + + let components = current.Create result (SetResult<'U> result) + + while (not result.Halted) && (enumerator.MoveNext ()) do + if components.ProcessNext (enumerator.Current) then + f result.Current + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let enumerator = enumerable.GetEnumerator () let result = Result<'U> () - let components = current.Create result (Tail<'U> result) + let components = current.Create result (SetResult<'U> result) let mutable state = initialState while (not result.Halted) && (enumerator.MoveNext ()) do @@ -1066,6 +1053,13 @@ namespace Microsoft.FSharp.Collections override this.Append source = Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) + override this.Iter (f:'T->unit) : unit = + let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) + let enumerator = enumerable.GetEnumerator () + + while enumerator.MoveNext () do + f enumerator.Current + override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder @@ -1078,11 +1072,23 @@ namespace Microsoft.FSharp.Collections state + let create enumerable current = + Helpers.upcastEnumerable (Enumerable(enumerable, current)) + module Array = - type Enumerator<'T,'U>(array:array<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let mutable idx = 0 + let mutable array = Unchecked.defaultof<_> + + let mutable initMoveNext = Unchecked.defaultof<_> + do + initMoveNext <- + fun () -> + result.SeqState <- SeqProcessNextStates.InProcess + array <- delayedArray () + initMoveNext <- ignore let rec moveNext () = if (not result.Halted) && idx < array.Length then @@ -1098,27 +1104,39 @@ namespace Microsoft.FSharp.Collections interface IEnumerator with member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess + initMoveNext () moveNext () - type Enumerable<'T,'U>(array:array<'T>, current:SeqComponentFactory<'T,'U>) = + type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(array, current.Create result (Tail<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result (SetResult<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.upcastEnumerable (new Enumerable<'T,'V>(array, ComposedFactory.Combine current next)) + Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) + + override this.Iter (f:'U->unit) : unit = + let mutable idx = 0 + let result = Result<'U> () + let components = current.Create result (SetResult<'U> result) + + let array = delayedArray () + while (not result.Halted) && (idx < array.Length) do + if components.ProcessNext array.[idx] then + f result.Current + idx <- idx + 1 override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let mutable idx = 0 let result = Result<'U> () - let components = current.Create result (Tail<'U> result) + let components = current.Create result (SetResult<'U> result) + let array = delayedArray () let mutable state = initialState while (not result.Halted) && (idx < array.Length) do if components.ProcessNext array.[idx] then @@ -1127,6 +1145,18 @@ namespace Microsoft.FSharp.Collections state + let createDelayed (delayedArray:unit->array<'T>) (current:SeqComponentFactory<'T,'U>) = + Helpers.upcastEnumerable (Enumerable(delayedArray, current)) + + let create (array:array<'T>) (current:SeqComponentFactory<'T,'U>) = + createDelayed (fun () -> array) current + + let createDelayedId (delayedArray:unit -> array<'T>) = + createDelayed delayedArray (IdentityFactory ()) + + let createId (array:array<'T>) = + create array (IdentityFactory ()) + module List = type Enumerator<'T,'U>(alist:list<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) @@ -1157,16 +1187,33 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (Tail<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (SetResult<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) + override this.Iter (f:'U->unit) : unit = + let result = Result<'U> () + let components = current.Create result (SetResult<'U> result) + + let rec fold lst = + match result.Halted, lst with + | true, _ + | false, [] -> () + | false, hd :: tl -> + if components.ProcessNext hd then + f result.Current + fold tl + else + fold tl + + fold alist + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let result = Result<'U> () - let components = current.Create result (Tail<'U> result) + let components = current.Create result (SetResult<'U> result) let rec fold state lst = match result.Halted, lst with @@ -1180,6 +1227,9 @@ namespace Microsoft.FSharp.Collections fold initialState alist + let create alist current = + Helpers.upcastEnumerable (Enumerable(alist, current)) + module Unfold = type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:SeqComponent<'T,'U>, signal:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) @@ -1207,16 +1257,33 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (Tail<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (SetResult<'U> result), result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + override this.Iter (f:'U->unit) : unit = + let result = Result<'U> () + let components = current.Create result (SetResult<'U> result) + + let rec fold current = + match result.Halted, generator current with + | true, _ + | false, None -> () + | false, Some (item, next) -> + if components.ProcessNext item then + f result.Current + fold next + else + fold next + + fold state + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let result = Result<'U> () - let components = current.Create result (Tail<'U> result) + let components = current.Create result (SetResult<'U> result) let rec fold state current = match result.Halted, generator current with @@ -1294,16 +1361,34 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (Tail<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (SetResult<'U> result), result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + override this.Iter (iter:'U->unit) : unit = + let result = Result<'U> () + let components = current.Create result (SetResult<'U> result) + + let mutable idx = -1 + let terminatingIdx = getTerminatingIdx count + + let mutable maybeSkipping = true + + while (not result.Halted) && (idx < terminatingIdx) do + if maybeSkipping then + maybeSkipping <- components.Skipping () + + if (not maybeSkipping) && (components.ProcessNext (f (idx+1))) then + iter result.Current + + idx <- idx + 1 + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let result = Result<'U> () - let components = current.Create result (Tail<'U> result) + let components = current.Create result (SetResult<'U> result) let mutable idx = -1 let terminatingIdx = getTerminatingIdx count @@ -1385,6 +1470,12 @@ namespace Microsoft.FSharp.Collections override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) + override this.Iter (f:'T->unit): unit = + let enumerator = (Helpers.upcastEnumerable this).GetEnumerator () + + while enumerator.MoveNext () do + f enumerator.Current + override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder @@ -1429,9 +1520,13 @@ namespace Microsoft.FSharp.Collections [] let iter f (source : seq<'T>) = checkNonNull "source" source - use e = source.GetEnumerator() - while e.MoveNext() do - f e.Current + checkNonNull "source" source + match source with + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Iter f + | _ -> + use e = source.GetEnumerator() + while e.MoveNext() do + f e.Current [] let item i (source : seq<'T>) = @@ -1521,9 +1616,9 @@ namespace Microsoft.FSharp.Collections checkNonNull "source" source match source with | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Compose createSeqComponent - | :? array<'T> as a -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Array.Enumerable<_,_>(a, createSeqComponent)) - | :? list<'T> as a -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.List.Enumerable<_,_>(a, createSeqComponent)) - | _ -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Enumerable.Enumerable<_,_>(source, createSeqComponent)) + | :? array<'T> as a -> SeqComposer.Array.create a createSeqComponent + | :? list<'T> as a -> SeqComposer.List.create a createSeqComponent + | _ -> SeqComposer.Enumerable.create source createSeqComponent [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = @@ -1738,7 +1833,7 @@ namespace Microsoft.FSharp.Collections [] let ofArray (source : 'T array) = checkNonNull "source" source - mkSeq (fun () -> IEnumerator.ofArray source) + SeqComposer.Array.createId source [] let toArray (source : seq<'T>) = @@ -2013,26 +2108,29 @@ namespace Microsoft.FSharp.Collections [] let sortBy keyf source = checkNonNull "source" source - mkDelayedSeq (fun () -> + let delayedSort () = let array = source |> toArray Array.stableSortInPlaceBy keyf array - array :> seq<_>) + array + SeqComposer.Array.createDelayedId delayedSort [] let sort source = checkNonNull "source" source - mkDelayedSeq (fun () -> + let delayedSort () = let array = source |> toArray Array.stableSortInPlace array - array :> seq<_>) + array + SeqComposer.Array.createDelayedId delayedSort [] let sortWith f source = checkNonNull "source" source - mkDelayedSeq (fun () -> + let delayedSort () = let array = source |> toArray Array.stableSortInPlaceWith f array - array :> seq<_>) + array + SeqComposer.Array.createDelayedId delayedSort [] let inline sortByDescending keyf source = @@ -2098,12 +2196,11 @@ namespace Microsoft.FSharp.Collections [] let inline average (source: seq< ^a>) : ^a = checkNonNull "source" source - use e = source.GetEnumerator() let mutable acc = LanguagePrimitives.GenericZero< ^a> let mutable count = 0 - while e.MoveNext() do - acc <- Checked.(+) acc e.Current - count <- count + 1 + source |> iter (fun current -> + acc <- Checked.(+) acc current + count <- count + 1) if count = 0 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString LanguagePrimitives.DivideByInt< ^a> acc count @@ -2309,16 +2406,20 @@ namespace Microsoft.FSharp.Collections [] let rev source = checkNonNull "source" source - mkDelayedSeq (fun () -> - let array = source |> toArray + let delayedReverse () = + let array = source |> toArray Array.Reverse array - array :> seq<_>) + array + SeqComposer.Array.createDelayedId delayedReverse [] - let permute f (source : seq<_>) = + let permute f (source:seq<_>) = checkNonNull "source" source - mkDelayedSeq (fun () -> - source |> toArray |> Array.permute f :> seq<_>) + let delayedPermute () = + source + |> toArray + |> Array.permute f + SeqComposer.Array.createDelayedId delayedPermute [] let mapFold<'T,'State,'Result> (f: 'State -> 'T -> 'Result * 'State) acc source = From 65f9c842a1beb77b91dff5bd23a97d6e5f50d45a Mon Sep 17 00:00:00 2001 From: liboz Date: Sat, 15 Oct 2016 17:34:13 +0200 Subject: [PATCH 13/59] making identity more efficient Updated NoNeedToTailcall for Seq.iter changes Added OnComplete calls to Iter and Folds Experimental ForEach Currently this is only implemented on Array. This adds some public surface to the SeqComposer which may be removed. Fixed signature file, so can now use object expression Provided all ForEach implementations Removed Fold Remove Iter --- src/fsharp/FSharp.Core/seq.fs | 472 +++++++++--------- src/fsharp/FSharp.Core/seq.fsi | 24 + ...tailcalls.NoNeedToTailcall.output.test.bsl | 2 +- 3 files changed, 263 insertions(+), 235 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 490d1fe808f..0aa5f40c43d 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -448,9 +448,6 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = -// type ISeqEnumerable<'T> = -// abstract member Fold<'State> : folder:('State->'T->'State) -> state:'State -> 'State - module SeqComposer = open IEnumerator @@ -458,6 +455,27 @@ namespace Microsoft.FSharp.Collections abstract OnComplete : unit -> unit abstract OnDispose : unit -> unit + type ISeqPipeline = + abstract StopFurtherProcessing : unit -> unit + + [] + type SeqConsumer<'T,'U> () = + abstract ProcessNext : input:'T -> bool + + interface ISeqComponent with + member __.OnComplete() = () + member __.OnDispose() = () + + [] + type AccumulatingConsumer<'T, 'U>(initialState:'U) = + inherit SeqConsumer<'T,'T>() + + member val Accumulator = initialState with get, set + + [] + type SeqEnumerable<'T>() = + abstract member ForEach<'a when 'a :> SeqConsumer<'T,'T>> : f:(ISeqPipeline->'a) -> 'a + module Helpers = // used for performance reasons; these are not recursive calls, so should be safe // ** it should be noted that potential changes to the f# compiler may render this function @@ -470,21 +488,8 @@ namespace Microsoft.FSharp.Collections let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) let inline upcastISeqComponent (t:#ISeqComponent) : ISeqComponent = (# "" t : ISeqComponent #) + let inline upcastSeqConsumer (t:#SeqConsumer<'a,'b>) : SeqConsumer<'a,'b> = (# "" t : SeqConsumer<'a,'b> #) - type SeqProcessNextStates = - | InProcess = 0 - | NotStarted = 1 - | Finished = 2 - - type Result<'T>() = - let mutable halted = false - - member val SeqState = SeqProcessNextStates.NotStarted with get, set - - member __.StopFurtherProcessing () = halted <- true - member __.Halted = halted - - member val Current = Unchecked.defaultof<'T> with get, set let seqComponentTail = { new ISeqComponent with @@ -492,14 +497,15 @@ namespace Microsoft.FSharp.Collections member __.OnDispose() = () } type [] SeqComponentFactory<'T,'U> () = - abstract Create<'V> : Result<'V> -> SeqComponent<'U,'V> -> SeqComponent<'T,'V> + abstract Create<'V> : ISeqPipeline -> SeqConsumer<'U,'V> -> SeqConsumer<'T,'V> abstract IsIdentity : bool default __.IsIdentity = false and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>) = inherit SeqComponentFactory<'T,'V> () - override __.Create<'W> (result:Result<'W>) (next:SeqComponent<'V,'W>) : SeqComponent<'T,'W> = first.Create result (second.Create result next) + override __.Create<'W> (result:ISeqPipeline) (next:SeqConsumer<'V,'W>) : SeqConsumer<'T,'W> = + first.Create result (second.Create result next) static member Combine (first:SeqComponentFactory<'T,'U>) (second:SeqComponentFactory<'U,'V>) : SeqComponentFactory<'T,'V> = let castToTV (factory:obj) = @@ -513,83 +519,89 @@ namespace Microsoft.FSharp.Collections and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Choose (filter, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = upcast Choose (filter, next) and DistinctFactory<'T when 'T: equality> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Distinct (next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Distinct (next) and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast DistinctBy (keyFunction, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast DistinctBy (keyFunction, next) and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Except (itemsToExclude, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Except (itemsToExclude, next) and FilterFactory<'T> (filter:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = next.CreateFilter filter + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = + match next with + | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter + | _ -> upcast Filter (filter, next) and IdentityFactory<'T> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = next.CreateMap id + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Identity (next) override __.IsIdentity = true and MapFactory<'T,'U> (map:'T->'U) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = next.CreateMap map + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = + match next with + | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map + | _ -> upcast Map<_,_,_> (map, next) and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map2First (map, input2, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'First,'V> = upcast Map2First (map, input2, result, next) and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = inherit SeqComponentFactory<'Second,'U> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'Second,'V> = upcast Map2Second (map, input1, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'Second,'V> = upcast Map2Second (map, input1, result, next) and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map3 (map, input2, input3, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'First,'V> = upcast Map3 (map, input2, input3, result, next) and MapiFactory<'T,'U> (mapi:int->'T->'U) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Mapi (mapi, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = upcast Mapi (mapi, next) and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Mapi2 (map, input2, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'First,'V> = upcast Mapi2 (map, input2, result, next) and PairwiseFactory<'T> () = inherit SeqComponentFactory<'T,'T*'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T*'T,'V>) : SeqComponent<'T,'V> = upcast Pairwise next + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T*'T,'V>) : SeqConsumer<'T,'V> = upcast Pairwise next and SkipFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Skip (count, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Skip (count, next) and SkipWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast SkipWhile (predicate, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast SkipWhile (predicate, next) and TakeWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast TakeWhile (predicate, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast TakeWhile (predicate, result, next) and TakeFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Take (count, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Take (count, result, next) and TailFactory<'T> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Tail<'T,'V> (next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Tail<'T,'V> (next) and TruncateFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Truncate (count, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Truncate (count, result, next) and [] SeqComponent<'T,'U> (next:ISeqComponent) = - abstract ProcessNext : input:'T -> bool + inherit SeqConsumer<'T,'U>() // Seq.init(Infinite)? lazily uses Current. The only SeqComposer component that can do that is Skip // and it can only do it at the start of a sequence @@ -607,7 +619,7 @@ namespace Microsoft.FSharp.Collections default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) - and Choose<'T,'U,'V> (choose:'T->option<'U>, next:SeqComponent<'U,'V>) = + and Choose<'T,'U,'V> (choose:'T->option<'U>, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = @@ -615,7 +627,7 @@ namespace Microsoft.FSharp.Collections | Some value -> Helpers.avoidTailCall (next.ProcessNext value) | None -> false - and Distinct<'T,'V when 'T: equality> (next:SeqComponent<'T,'V>) = + and Distinct<'T,'V when 'T: equality> (next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) @@ -626,7 +638,7 @@ namespace Microsoft.FSharp.Collections else false - and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:SeqComponent<'T,'V>) = + and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) @@ -637,7 +649,7 @@ namespace Microsoft.FSharp.Collections else false - and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:SeqComponent<'T,'V>) = + and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) @@ -648,7 +660,7 @@ namespace Microsoft.FSharp.Collections else false - and Filter<'T,'V> (filter:'T->bool, next:SeqComponent<'T,'V>) = + and Filter<'T,'V> (filter:'T->bool, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) @@ -659,7 +671,7 @@ namespace Microsoft.FSharp.Collections else false - and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:SeqComponent<'U,'V>) = + and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = @@ -668,7 +680,13 @@ namespace Microsoft.FSharp.Collections else false - and Map<'T,'U,'V> (map:'T->'U, next:SeqComponent<'U,'V>) = + and Identity<'T,'V> (next:SeqConsumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + Helpers.avoidTailCall (next.ProcessNext input) + + and Map<'T,'U,'V> (map:'T->'U, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'T,'V>(next) override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) @@ -676,7 +694,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = Helpers.avoidTailCall (next.ProcessNext (map input)) - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = + and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () @@ -696,7 +714,7 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:Result<'V>, next:SeqComponent<'U,'V>) = + and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'Second,'V>(next) let input1 = enumerable1.GetEnumerator () @@ -716,7 +734,7 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:Result<'V>, next:SeqComponent<'U,'V>) = + and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () @@ -740,7 +758,7 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqComponent<'U,'V>) = + and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = @@ -750,7 +768,7 @@ namespace Microsoft.FSharp.Collections else false - and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:SeqComponent<'U,'V>) = + and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'T,'V>(next) let mutable idx = 0 @@ -760,7 +778,7 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) - and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = + and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'First,'V>(next) let mutable idx = 0 @@ -782,7 +800,7 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and Pairwise<'T,'V> (next:SeqComponent<'T*'T,'V>) = + and Pairwise<'T,'V> (next:SeqConsumer<'T*'T,'V>) = inherit SeqComponent<'T,'V>(next) let mutable isFirst = true @@ -798,7 +816,7 @@ namespace Microsoft.FSharp.Collections lastValue <- input Helpers.avoidTailCall (next.ProcessNext currentPair) - and Skip<'T,'V> (skipCount:int, next:SeqComponent<'T,'V>) = + and Skip<'T,'V> (skipCount:int, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let mutable count = 0 @@ -825,7 +843,7 @@ namespace Microsoft.FSharp.Collections [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] (Helpers.upcastISeqComponent next).OnComplete () - and SkipWhile<'T,'V> (predicate:'T->bool, next:SeqComponent<'T,'V>) = + and SkipWhile<'T,'V> (predicate:'T->bool, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let mutable skip = true @@ -840,7 +858,7 @@ namespace Microsoft.FSharp.Collections else Helpers.avoidTailCall (next.ProcessNext input) - and Take<'T,'V> (takeCount:int, result:Result<'V>, next:SeqComponent<'T,'V>) = + and Take<'T,'V> (takeCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>) = inherit Truncate<'T, 'V>(takeCount, result, next) interface ISeqComponent with @@ -851,7 +869,7 @@ namespace Microsoft.FSharp.Collections [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] (Helpers.upcastISeqComponent next).OnComplete () - and TakeWhile<'T,'V> (predicate:'T->bool, result:Result<'V>, next:SeqComponent<'T,'V>) = + and TakeWhile<'T,'V> (predicate:'T->bool, result:ISeqPipeline, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = @@ -861,7 +879,7 @@ namespace Microsoft.FSharp.Collections result.StopFurtherProcessing () false - and Tail<'T, 'V> (next:SeqComponent<'T,'V>) = + and Tail<'T, 'V> (next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let mutable first = true @@ -879,7 +897,7 @@ namespace Microsoft.FSharp.Collections invalidArg "source" (SR.GetString(SR.notEnoughElements)) (Helpers.upcastISeqComponent next).OnComplete () - and Truncate<'T,'V> (truncateCount:int, result:Result<'V>, next:SeqComponent<'T,'V>) = + and Truncate<'T,'V> (truncateCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let mutable count = 0 @@ -896,9 +914,24 @@ namespace Microsoft.FSharp.Collections result.StopFurtherProcessing () false + type SeqProcessNextStates = + | InProcess = 0 + | NotStarted = 1 + | Finished = 2 + + type Result<'T>() = + let mutable halted = false + + member val Current = Unchecked.defaultof<'T> with get, set + member val SeqState = SeqProcessNextStates.NotStarted with get, set + member __.Halted = halted + + interface ISeqPipeline with + member __.StopFurtherProcessing () = halted <- true + // SetResult<> is used at the end of the chain of SeqComponents to assign the final value type SetResult<'T> (result:Result<'T>) = - inherit SeqComponent<'T,'T>(seqComponentTail) + inherit SeqConsumer<'T,'T>() override __.ProcessNext (input:'T) : bool = result.Current <- input @@ -926,9 +959,10 @@ namespace Microsoft.FSharp.Collections | _ -> failwith "library implementation error: all states should have been handled" and [] EnumerableBase<'T> () = + inherit SeqEnumerable<'T>() + abstract member Compose<'U> : (SeqComponentFactory<'T,'U>) -> IEnumerable<'U> abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> - abstract member Iter : f:('T->unit) -> unit default this.Append source = Helpers.upcastEnumerable (AppendEnumerable [this; source]) @@ -941,7 +975,8 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = failwith "library implementation error: derived class should implement (should be abstract)" - and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + + and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = inherit EnumeratorBase<'U>(result, seqComponent) let rec moveNext () = @@ -978,30 +1013,21 @@ namespace Microsoft.FSharp.Collections override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) - override this.Iter (f:'U->unit) : unit = - let enumerator = enumerable.GetEnumerator () - let result = Result<'U> () - - let components = current.Create result (SetResult<'U> result) - - while (not result.Halted) && (enumerator.MoveNext ()) do - if components.ProcessNext (enumerator.Current) then - f result.Current - - override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - - let enumerator = enumerable.GetEnumerator () - let result = Result<'U> () - - let components = current.Create result (SetResult<'U> result) - - let mutable state = initialState - while (not result.Halted) && (enumerator.MoveNext ()) do - if components.ProcessNext (enumerator.Current) then - state <- folder'.Invoke (state, result.Current) + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + let mutable halted = false + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } + + let result = f pipeline + let consumer = current.Create pipeline result - state + use enumerator = enumerable.GetEnumerator () + while (not halted) && (enumerator.MoveNext ()) do + consumer.ProcessNext enumerator.Current |> ignore + + (Helpers.upcastISeqComponent consumer).OnComplete () + + result and AppendEnumerator<'T> (sources:list>) = let sources = sources |> List.rev @@ -1053,30 +1079,29 @@ namespace Microsoft.FSharp.Collections override this.Append source = Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) - override this.Iter (f:'T->unit) : unit = - let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) - let enumerator = enumerable.GetEnumerator () - - while enumerator.MoveNext () do - f enumerator.Current + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = + let mutable halted = false + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - + let result = f pipeline + let consumer = Helpers.upcastSeqConsumer result + let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) - let enumerator = enumerable.GetEnumerator () + use enumerator = enumerable.GetEnumerator () - let mutable state = initialState while enumerator.MoveNext () do - state <- folder'.Invoke (state, enumerator.Current) - - state + consumer.ProcessNext enumerator.Current |> ignore + + (Helpers.upcastISeqComponent consumer).OnComplete () + + result let create enumerable current = Helpers.upcastEnumerable (Enumerable(enumerable, current)) module Array = - type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let mutable idx = 0 @@ -1118,32 +1143,24 @@ namespace Microsoft.FSharp.Collections override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) - override this.Iter (f:'U->unit) : unit = + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = let mutable idx = 0 - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) - - let array = delayedArray () - while (not result.Halted) && (idx < array.Length) do - if components.ProcessNext array.[idx] then - f result.Current - idx <- idx + 1 + let mutable halted = false - override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - - let mutable idx = 0 - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } + + let result = f pipeline + let consumer = current.Create pipeline result let array = delayedArray () - let mutable state = initialState - while (not result.Halted) && (idx < array.Length) do - if components.ProcessNext array.[idx] then - state <- folder'.Invoke (state, result.Current) + while (not halted) && (idx < array.Length) do + consumer.ProcessNext array.[idx] |> ignore idx <- idx + 1 - - state + + (Helpers.upcastISeqComponent consumer).OnComplete () + + result let createDelayed (delayedArray:unit->array<'T>) (current:SeqComponentFactory<'T,'U>) = Helpers.upcastEnumerable (Enumerable(delayedArray, current)) @@ -1158,7 +1175,7 @@ namespace Microsoft.FSharp.Collections create array (IdentityFactory ()) module List = - type Enumerator<'T,'U>(alist:list<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + type Enumerator<'T,'U>(alist:list<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let mutable list = alist @@ -1192,46 +1209,31 @@ namespace Microsoft.FSharp.Collections override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) - override this.Iter (f:'U->unit) : unit = - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) - - let rec fold lst = - match result.Halted, lst with - | true, _ - | false, [] -> () - | false, hd :: tl -> - if components.ProcessNext hd then - f result.Current - fold tl - else - fold tl - - fold alist + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + let mutable halted = false + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) + let result = f pipeline + let consumer = current.Create pipeline result - let rec fold state lst = - match result.Halted, lst with + let rec iterate lst = + match halted, lst with | true, _ - | false, [] -> state + | false, [] -> (Helpers.upcastISeqComponent consumer).OnComplete () | false, hd :: tl -> - if components.ProcessNext hd then - fold (folder'.Invoke (state, result.Current)) tl - else - fold state tl + consumer.ProcessNext hd |> ignore + iterate tl - fold initialState alist + iterate alist + + result let create alist current = Helpers.upcastEnumerable (Enumerable(alist, current)) module Unfold = - type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:SeqComponent<'T,'U>, signal:Result<'U>) = + type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:SeqConsumer<'T,'U>, signal:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) let mutable current = state @@ -1262,40 +1264,25 @@ namespace Microsoft.FSharp.Collections override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) - override this.Iter (f:'U->unit) : unit = - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + let mutable halted = false + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - let rec fold current = - match result.Halted, generator current with - | true, _ - | false, None -> () - | false, Some (item, next) -> - if components.ProcessNext item then - f result.Current - fold next - else - fold next + let result = f pipeline + let consumer = current.Create pipeline result - fold state - - override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) - - let rec fold state current = - match result.Halted, generator current with + let rec iterate current = + match halted, generator current with | true, _ - | false, None -> state + | false, None -> (Helpers.upcastISeqComponent consumer).OnComplete () | false, Some (item, next) -> - if components.ProcessNext item then - fold (folder'.Invoke (state, result.Current)) next - else - fold state next + consumer.ProcessNext item |> ignore + iterate next - fold initialState state + iterate state + + result module Init = // The original implementation of "init" delayed the calculation of Current, and so it was possible @@ -1319,9 +1306,17 @@ namespace Microsoft.FSharp.Collections else System.Int32.MaxValue - type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:SeqComponent<'T,'U>, signal:Result<'U>) = + let makeIsSkipping (consumer:SeqConsumer<'T,'U>) = + match consumer with + | :? SeqComponent<'T,'U> as c -> c.Skipping + | _ -> fun () -> false + + type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:SeqConsumer<'T,'U>, signal:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) + let isSkipping = + makeIsSkipping seqComponent + let terminatingIdx = getTerminatingIdx count @@ -1335,7 +1330,7 @@ namespace Microsoft.FSharp.Collections if maybeSkipping then // Skip can only is only checked at the start of the sequence, so once // triggered, we stay triggered. - maybeSkipping <- seqComponent.Skipping () + maybeSkipping <- isSkipping () if maybeSkipping then moveNext () @@ -1366,46 +1361,34 @@ namespace Microsoft.FSharp.Collections override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) - override this.Iter (iter:'U->unit) : unit = - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) + override this.ForEach (createResult:ISeqPipeline->#SeqConsumer<'U,'U>) = + let mutable halted = false + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } + + let result = createResult pipeline + let consumer = current.Create pipeline result let mutable idx = -1 let terminatingIdx = getTerminatingIdx count - - let mutable maybeSkipping = true - - while (not result.Halted) && (idx < terminatingIdx) do - if maybeSkipping then - maybeSkipping <- components.Skipping () - if (not maybeSkipping) && (components.ProcessNext (f (idx+1))) then - iter result.Current + let isSkipping = + makeIsSkipping consumer - idx <- idx + 1 - - override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) - - let mutable idx = -1 - let terminatingIdx = getTerminatingIdx count - let mutable maybeSkipping = true - let mutable state = initialState - while (not result.Halted) && (idx < terminatingIdx) do + while (not halted) && (idx < terminatingIdx) do if maybeSkipping then - maybeSkipping <- components.Skipping () + maybeSkipping <- isSkipping () - if (not maybeSkipping) && (components.ProcessNext (f (idx+1))) then - state <- folder'.Invoke (state, result.Current) + if (not maybeSkipping) then + consumer.ProcessNext (f (idx+1)) |> ignore idx <- idx + 1 - - state + + (Helpers.upcastISeqComponent consumer).OnComplete () + + result let upto lastOption f = match lastOption with @@ -1470,22 +1453,22 @@ namespace Microsoft.FSharp.Collections override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) - override this.Iter (f:'T->unit): unit = - let enumerator = (Helpers.upcastEnumerable this).GetEnumerator () - - while enumerator.MoveNext () do - f enumerator.Current + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = + let mutable halted = false + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - - let enumerator = (Helpers.upcastEnumerable this).GetEnumerator () + let result = f pipeline + let consumer = Helpers.upcastSeqConsumer result - let mutable state = initialState - while enumerator.MoveNext () do - state <- folder'.Invoke (state, enumerator.Current) + use enumerator = (Helpers.upcastEnumerable this).GetEnumerator () - state + while enumerator.MoveNext () do + consumer.ProcessNext enumerator.Current |> ignore + + (Helpers.upcastISeqComponent consumer).OnComplete () + + result #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions @@ -1519,10 +1502,13 @@ namespace Microsoft.FSharp.Collections [] let iter f (source : seq<'T>) = - checkNonNull "source" source checkNonNull "source" source match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Iter f + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> + s.ForEach (fun _ -> + { new SeqComposer.SeqConsumer<'T,'T> () with + override this.ProcessNext value = + f value; true }) |> ignore | _ -> use e = source.GetEnumerator() while e.MoveNext() do @@ -1749,7 +1735,15 @@ namespace Microsoft.FSharp.Collections let fold<'T,'State> f (x:'State) (source:seq<'T>) = checkNonNull "source" source match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Fold f x + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) + let total = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'State> (x) with + override this.ProcessNext value = + this.Accumulator <- f.Invoke (this.Accumulator, value) + true }) + total.Accumulator | _ -> use e = source.GetEnumerator() let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) @@ -2178,12 +2172,22 @@ namespace Microsoft.FSharp.Collections else mkDelayedSeq (fun () -> countByRefType keyf source) [] - let inline sum (source: seq< ^a>) : ^a = - use e = source.GetEnumerator() - let mutable acc = LanguagePrimitives.GenericZero< ^a> - while e.MoveNext() do - acc <- Checked.(+) acc e.Current - acc + let inline sum (source:seq<'a>) : 'a = + match source with + | :? SeqComposer.SeqEnumerable<'a> as s -> + let total = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator value + true }) + total.Accumulator + | _ -> + use e = source.GetEnumerator() + let mutable acc = LanguagePrimitives.GenericZero< ^a> + while e.MoveNext() do + acc <- Checked.(+) acc e.Current + acc [] let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index f05e9db76dd..161cdcdc1aa 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -13,6 +13,30 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = + module SeqComposer = + type ISeqComponent = + abstract OnComplete : unit -> unit + abstract OnDispose : unit -> unit + + type ISeqPipeline = + abstract StopFurtherProcessing : unit -> unit + + [] + type SeqConsumer<'T,'U> = + new : unit -> SeqConsumer<'T,'U> + abstract ProcessNext : input:'T -> bool + interface ISeqComponent + + [] + type AccumulatingConsumer<'T,'U> = + inherit SeqConsumer<'T,'T> + new : initialState:'U -> AccumulatingConsumer<'T,'U> + member Accumulator : 'U + member Accumulator : 'U with set + + [] + type SeqEnumerable<'T> = + abstract member ForEach<'a when 'a :> SeqConsumer<'T,'T>> : f:(ISeqPipeline->'a) -> 'a /// Returns a new sequence that contains the cartesian product of the two input sequences. /// The first sequence. diff --git a/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl b/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl index 785a337a2f4..983ebaa85f5 100644 --- a/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl +++ b/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl @@ -41,7 +41,7 @@ value simpleLibraryCall9 at line 63 does not make a critical tailcall value simpleLibraryCall10 at line 65 may make a critical tailcall value simpleLibraryCall11 at line 66 does not make a critical tailcall value simpleLibraryCall12 at line 67 does not make a critical tailcall -value simpleLibraryCall13 at line 68 does not make a critical tailcall +value simpleLibraryCall13 at line 68 may make a critical tailcall value simpleLibraryUse14 at line 69 does not make a critical tailcall value simpleLibraryUse15 at line 70 does not make a critical tailcall value simpleLibraryUse16 at line 71 does not make a critical tailcall From 18fd79ae4449b62050b2c0e95197824f367a4a92 Mon Sep 17 00:00:00 2001 From: liboz Date: Tue, 18 Oct 2016 20:18:13 -0400 Subject: [PATCH 14/59] sumby, average, averageby, max, maxby, min, minby --- src/fsharp/FSharp.Core/seq.fs | 268 +++++++++++++++++++++++++--------- 1 file changed, 196 insertions(+), 72 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 0aa5f40c43d..557f7b59e75 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -2191,66 +2191,150 @@ namespace Microsoft.FSharp.Collections [] let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U = - use e = source.GetEnumerator() - let mutable acc = LanguagePrimitives.GenericZero< ^U> - while e.MoveNext() do - acc <- Checked.(+) acc (f e.Current) - acc + match source with + | :? SeqComposer.SeqEnumerable<'T> as s -> + let total = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator (f value) + true }) + total.Accumulator + | _ -> + use e = source.GetEnumerator() + let mutable acc = LanguagePrimitives.GenericZero< ^U> + while e.MoveNext() do + acc <- Checked.(+) acc (f e.Current) + acc [] let inline average (source: seq< ^a>) : ^a = - checkNonNull "source" source - let mutable acc = LanguagePrimitives.GenericZero< ^a> - let mutable count = 0 - source |> iter (fun current -> - acc <- Checked.(+) acc current - count <- count + 1) - if count = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - LanguagePrimitives.DivideByInt< ^a> acc count + match source with + | :? SeqComposer.SeqEnumerable<'a> as s -> + let mutable count = 0 + let total = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator value + count <- count + 1 + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if count = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + LanguagePrimitives.DivideByInt< ^a> total.Accumulator count + | _ -> + checkNonNull "source" source + let mutable acc = LanguagePrimitives.GenericZero< ^a> + let mutable count = 0 + source |> iter (fun current -> + acc <- Checked.(+) acc current + count <- count + 1) + if count = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + LanguagePrimitives.DivideByInt< ^a> acc count [] let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = - checkNonNull "source" source - use e = source.GetEnumerator() - let mutable acc = LanguagePrimitives.GenericZero< ^U> - let mutable count = 0 - while e.MoveNext() do - acc <- Checked.(+) acc (f e.Current) - count <- count + 1 - if count = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - LanguagePrimitives.DivideByInt< ^U> acc count + match source with + | :? SeqComposer.SeqEnumerable<'T> as s -> + let mutable count = 0 + let total = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator (f value) + count <- count + 1 + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if count = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + LanguagePrimitives.DivideByInt< ^U> total.Accumulator count + | _ -> + checkNonNull "source" source + use e = source.GetEnumerator() + let mutable acc = LanguagePrimitives.GenericZero< ^U> + let mutable count = 0 + while e.MoveNext() do + acc <- Checked.(+) acc (f e.Current) + count <- count + 1 + if count = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + LanguagePrimitives.DivideByInt< ^U> acc count [] let inline min (source: seq<_>) = - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - let mutable acc = e.Current - while e.MoveNext() do - let curr = e.Current - if curr < acc then - acc <- curr - acc + match source with + | :? SeqComposer.SeqEnumerable<'T> as s -> + let mutable first = false + let min = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + first <- false + if value < this.Accumulator then + this.Accumulator <- value + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + min.Accumulator + | _ -> + checkNonNull "source" source + use e = source.GetEnumerator() + if not (e.MoveNext()) then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + let mutable acc = e.Current + while e.MoveNext() do + let curr = e.Current + if curr < acc then + acc <- curr + acc [] let inline minBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - let first = e.Current - let mutable acc = f first - let mutable accv = first - while e.MoveNext() do - let currv = e.Current - let curr = f currv - if curr < acc then - acc <- curr - accv <- currv - accv + match source with + | :? SeqComposer.SeqEnumerable<'T> as s -> + let mutable first = false + let mutable acc = Unchecked.defaultof<'U> + let min = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + first <- false + let currValue = value + let curr = f currValue + if curr < acc then + acc <- curr + this.Accumulator <- value + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + min.Accumulator + | _ -> + checkNonNull "source" source + use e = source.GetEnumerator() + if not (e.MoveNext()) then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + let first = e.Current + let mutable acc = f first + let mutable accv = first + while e.MoveNext() do + let currv = e.Current + let curr = f currv + if curr < acc then + acc <- curr + accv <- currv + accv (* [] @@ -2271,33 +2355,73 @@ namespace Microsoft.FSharp.Collections *) [] let inline max (source: seq<_>) = - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - let mutable acc = e.Current - while e.MoveNext() do - let curr = e.Current - if curr > acc then - acc <- curr - acc + match source with + | :? SeqComposer.SeqEnumerable<'T> as s -> + let mutable first = false + let max = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + first <- false + if value > this.Accumulator then + this.Accumulator <- value + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + max.Accumulator + | _ -> + checkNonNull "source" source + use e = source.GetEnumerator() + if not (e.MoveNext()) then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + let mutable acc = e.Current + while e.MoveNext() do + let curr = e.Current + if curr > acc then + acc <- curr + acc [] let inline maxBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - let first = e.Current - let mutable acc = f first - let mutable accv = first - while e.MoveNext() do - let currv = e.Current - let curr = f currv - if curr > acc then - acc <- curr - accv <- currv - accv + match source with + | :? SeqComposer.SeqEnumerable<'T> as s -> + let mutable first = false + let mutable acc = Unchecked.defaultof<'U> + let min = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + first <- false + let currValue = value + let curr = f currValue + if curr > acc then + acc <- curr + this.Accumulator <- value + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + min.Accumulator + | _ -> + checkNonNull "source" source + use e = source.GetEnumerator() + if not (e.MoveNext()) then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + let first = e.Current + let mutable acc = f first + let mutable accv = first + while e.MoveNext() do + let currv = e.Current + let curr = f currv + if curr > acc then + acc <- curr + accv <- currv + accv (* From b8e94bfee5609cf68ad652c8a9062438ccd5beb0 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Wed, 19 Oct 2016 09:20:55 +0200 Subject: [PATCH 15/59] Removed overzelous upcastSeqConsumer PE verify says no. Appease the NoNeedToTailcall file --- src/fsharp/FSharp.Core/seq.fs | 6 ++---- .../analyses/tailcalls.NoNeedToTailcall.output.test.bsl | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 557f7b59e75..6e297614043 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -488,8 +488,6 @@ namespace Microsoft.FSharp.Collections let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) let inline upcastISeqComponent (t:#ISeqComponent) : ISeqComponent = (# "" t : ISeqComponent #) - let inline upcastSeqConsumer (t:#SeqConsumer<'a,'b>) : SeqConsumer<'a,'b> = (# "" t : SeqConsumer<'a,'b> #) - let seqComponentTail = { new ISeqComponent with @@ -1085,7 +1083,7 @@ namespace Microsoft.FSharp.Collections { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } let result = f pipeline - let consumer = Helpers.upcastSeqConsumer result + let consumer : SeqConsumer<'T,'T> = upcast result let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) use enumerator = enumerable.GetEnumerator () @@ -1459,7 +1457,7 @@ namespace Microsoft.FSharp.Collections { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } let result = f pipeline - let consumer = Helpers.upcastSeqConsumer result + let consumer : SeqConsumer<'T,'T> = upcast result use enumerator = (Helpers.upcastEnumerable this).GetEnumerator () diff --git a/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl b/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl index 983ebaa85f5..785a337a2f4 100644 --- a/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl +++ b/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl @@ -41,7 +41,7 @@ value simpleLibraryCall9 at line 63 does not make a critical tailcall value simpleLibraryCall10 at line 65 may make a critical tailcall value simpleLibraryCall11 at line 66 does not make a critical tailcall value simpleLibraryCall12 at line 67 does not make a critical tailcall -value simpleLibraryCall13 at line 68 may make a critical tailcall +value simpleLibraryCall13 at line 68 does not make a critical tailcall value simpleLibraryUse14 at line 69 does not make a critical tailcall value simpleLibraryUse15 at line 70 does not make a critical tailcall value simpleLibraryUse16 at line 71 does not make a critical tailcall From db169c20c0175e4de64da260d42407f30172c95b Mon Sep 17 00:00:00 2001 From: liboz Date: Thu, 20 Oct 2016 00:27:37 +0200 Subject: [PATCH 16/59] toComposer and implementing sum singleton identityfactory using tocomposer implementing previously implementing seq functions using toComposer. Also fixes a bug with the boolean checking first fix bug with bool --- src/fsharp/FSharp.Core/seq.fs | 334 +++++++++++++-------------------- src/fsharp/FSharp.Core/seq.fsi | 10 + 2 files changed, 144 insertions(+), 200 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 6e297614043..1a87fc29858 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -543,6 +543,8 @@ namespace Microsoft.FSharp.Collections override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Identity (next) override __.IsIdentity = true + static member IdentityFactory = IdentityFactory<'T>() + and MapFactory<'T,'U> (map:'T->'U) = inherit SeqComponentFactory<'T,'U> () override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = @@ -1167,10 +1169,10 @@ namespace Microsoft.FSharp.Collections createDelayed (fun () -> array) current let createDelayedId (delayedArray:unit -> array<'T>) = - createDelayed delayedArray (IdentityFactory ()) + createDelayed delayedArray IdentityFactory.IdentityFactory let createId (array:array<'T>) = - create array (IdentityFactory ()) + create array IdentityFactory.IdentityFactory module List = type Enumerator<'T,'U>(alist:list<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = @@ -1483,7 +1485,7 @@ namespace Microsoft.FSharp.Collections [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> = - SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Unfold.Enumerable<'T,'T,'State>(generator, state, SeqComposer.IdentityFactory ())) + SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Unfold.Enumerable<'T,'T,'State>(generator, state, SeqComposer.IdentityFactory.IdentityFactory)) [] let empty<'T> = (EmptyEnumerable :> seq<'T>) @@ -2168,172 +2170,124 @@ namespace Microsoft.FSharp.Collections #endif then mkDelayedSeq (fun () -> countByValueType keyf source) else mkDelayedSeq (fun () -> countByRefType keyf source) + + [] + let toComposer (source:seq<'T>): SeqComposer.SeqEnumerable<'T> = + checkNonNull "source" source + match source with + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(s, SeqComposer.IdentityFactory.IdentityFactory) + | :? array<'T> as a -> upcast SeqComposer.Array.Enumerable((fun () -> a), SeqComposer.IdentityFactory.IdentityFactory) + | :? list<'T> as a -> upcast SeqComposer.List.Enumerable(a, SeqComposer.IdentityFactory.IdentityFactory) + | _ -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(source, SeqComposer.IdentityFactory.IdentityFactory) [] let inline sum (source:seq<'a>) : 'a = - match source with - | :? SeqComposer.SeqEnumerable<'a> as s -> - let total = - s.ForEach (fun _ -> + let composedSource = toComposer source + let total = + composedSource.ForEach (fun _ -> { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with override this.ProcessNext value = this.Accumulator <- Checked.(+) this.Accumulator value true }) - total.Accumulator - | _ -> - use e = source.GetEnumerator() - let mutable acc = LanguagePrimitives.GenericZero< ^a> - while e.MoveNext() do - acc <- Checked.(+) acc e.Current - acc + total.Accumulator [] let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U = - match source with - | :? SeqComposer.SeqEnumerable<'T> as s -> - let total = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with - override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator (f value) - true }) - total.Accumulator - | _ -> - use e = source.GetEnumerator() - let mutable acc = LanguagePrimitives.GenericZero< ^U> - while e.MoveNext() do - acc <- Checked.(+) acc (f e.Current) - acc + let composedSource = toComposer source + let total = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator (f value) + true }) + total.Accumulator [] let inline average (source: seq< ^a>) : ^a = - match source with - | :? SeqComposer.SeqEnumerable<'a> as s -> - let mutable count = 0 - let total = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with - override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator value - count <- count + 1 - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if count = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - LanguagePrimitives.DivideByInt< ^a> total.Accumulator count - | _ -> - checkNonNull "source" source - let mutable acc = LanguagePrimitives.GenericZero< ^a> - let mutable count = 0 - source |> iter (fun current -> - acc <- Checked.(+) acc current - count <- count + 1) - if count = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - LanguagePrimitives.DivideByInt< ^a> acc count + let composedSource = toComposer source + + let mutable count = 0 + let total = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator value + count <- count + 1 + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if count = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + LanguagePrimitives.DivideByInt< ^a> total.Accumulator count [] let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = - match source with - | :? SeqComposer.SeqEnumerable<'T> as s -> - let mutable count = 0 - let total = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with - override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator (f value) - count <- count + 1 - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if count = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - LanguagePrimitives.DivideByInt< ^U> total.Accumulator count - | _ -> - checkNonNull "source" source - use e = source.GetEnumerator() - let mutable acc = LanguagePrimitives.GenericZero< ^U> - let mutable count = 0 - while e.MoveNext() do - acc <- Checked.(+) acc (f e.Current) - count <- count + 1 - if count = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - LanguagePrimitives.DivideByInt< ^U> acc count + let composedSource = toComposer source + let mutable count = 0 + let total = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator (f value) + count <- count + 1 + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if count = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + LanguagePrimitives.DivideByInt< ^U> total.Accumulator count [] let inline min (source: seq<_>) = - match source with - | :? SeqComposer.SeqEnumerable<'T> as s -> - let mutable first = false - let min = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = + let composedSource = toComposer source + + let mutable first = true + let min = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + if first then first <- false - if value < this.Accumulator then - this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - min.Accumulator - | _ -> - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - let mutable acc = e.Current - while e.MoveNext() do - let curr = e.Current - if curr < acc then - acc <- curr - acc + this.Accumulator <- value + elif value < this.Accumulator then + this.Accumulator <- value + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + min.Accumulator [] let inline minBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - match source with - | :? SeqComposer.SeqEnumerable<'T> as s -> - let mutable first = false - let mutable acc = Unchecked.defaultof<'U> - let min = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = + let composedSource = toComposer source + + let mutable first = true + let mutable acc = Unchecked.defaultof<'U> + let min = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + let currValue = value + let curr = f currValue + if first then first <- false - let currValue = value - let curr = f currValue + acc <- curr + this.Accumulator <- value + else if curr < acc then acc <- curr this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - min.Accumulator - | _ -> - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - let first = e.Current - let mutable acc = f first - let mutable accv = first - while e.MoveNext() do - let currv = e.Current - let curr = f currv - if curr < acc then - acc <- curr - accv <- currv - accv - + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + min.Accumulator (* [] let inline minValBy (f : 'T -> 'U) (source: seq<'T>) : 'U = @@ -2353,74 +2307,54 @@ namespace Microsoft.FSharp.Collections *) [] let inline max (source: seq<_>) = - match source with - | :? SeqComposer.SeqEnumerable<'T> as s -> - let mutable first = false - let max = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = + let composedSource = toComposer source + + let mutable first = true + let max = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + if first then first <- false + this.Accumulator <- value + else if value > this.Accumulator then this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - max.Accumulator - | _ -> - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - let mutable acc = e.Current - while e.MoveNext() do - let curr = e.Current - if curr > acc then - acc <- curr - acc + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + max.Accumulator [] let inline maxBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - match source with - | :? SeqComposer.SeqEnumerable<'T> as s -> - let mutable first = false - let mutable acc = Unchecked.defaultof<'U> - let min = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = + let composedSource = toComposer source + + let mutable first = true + let mutable acc = Unchecked.defaultof<'U> + let min = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + let currValue = value + let curr = f currValue + if first then first <- false - let currValue = value - let curr = f currValue + acc <- curr + this.Accumulator <- value + else if curr > acc then acc <- curr this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - min.Accumulator - | _ -> - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - let first = e.Current - let mutable acc = f first - let mutable accv = first - while e.MoveNext() do - let currv = e.Current - let curr = f currv - if curr > acc then - acc <- curr - accv <- currv - accv - + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + min.Accumulator (* [] diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index 161cdcdc1aa..cdcd83cd3a9 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -1146,6 +1146,16 @@ namespace Microsoft.FSharp.Collections [] val inline sortByDescending : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> when 'Key : comparison + /// Builds an SeqEnumerable from the given collection. + /// + /// The input sequence. + /// + /// The result SeqEnumerable. + /// + /// Thrown when the input sequence is null. + [] + val toComposer : source:seq<'T> -> SeqComposer.SeqEnumerable<'T> + /// Returns the sum of the elements in the sequence. /// /// The elements are summed using the + operator and Zero property associated with the generated type. From 4e3eb4130d5ca05cdf8116ba654d5f324e26a6c9 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 20 Oct 2016 07:55:58 +0200 Subject: [PATCH 17/59] Remove duplicated ISeqPipeline Just a straight cast when EnumerableBase Simplified Identity Avoid creating extra ref objects Using average as an example of using a tuple-like, but mutable, value type to tie the data closer together and avoid allocation. Ensuring that OnDispose is called from ForEach --- src/fsharp/FSharp.Core/seq.fs | 282 ++++++++++++++++----------------- src/fsharp/FSharp.Core/seq.fsi | 13 +- 2 files changed, 152 insertions(+), 143 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 1a87fc29858..eff58cc5ac5 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -466,11 +466,26 @@ namespace Microsoft.FSharp.Collections member __.OnComplete() = () member __.OnDispose() = () + [] + type MutableData<'a,'b> = + val mutable _1 : 'a + val mutable _2 : 'b + + new (a:'a, b: 'b) = { + _1 = a + _2 = b + } + [] - type AccumulatingConsumer<'T, 'U>(initialState:'U) = - inherit SeqConsumer<'T,'T>() + type AccumulatingConsumer<'T, 'U> = + inherit SeqConsumer<'T,'T> + + val mutable Accumulator : 'U - member val Accumulator = initialState with get, set + new (initialState) = { + inherit SeqConsumer<'T,'T>() + Accumulator = initialState + } [] type SeqEnumerable<'T>() = @@ -496,9 +511,6 @@ namespace Microsoft.FSharp.Collections type [] SeqComponentFactory<'T,'U> () = abstract Create<'V> : ISeqPipeline -> SeqConsumer<'U,'V> -> SeqConsumer<'T,'V> - abstract IsIdentity : bool - - default __.IsIdentity = false and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>) = inherit SeqComponentFactory<'T,'V> () @@ -506,14 +518,7 @@ namespace Microsoft.FSharp.Collections first.Create result (second.Create result next) static member Combine (first:SeqComponentFactory<'T,'U>) (second:SeqComponentFactory<'U,'V>) : SeqComponentFactory<'T,'V> = - let castToTV (factory:obj) = - match factory with - | :? SeqComponentFactory<'T,'V> as result -> result - | _ -> failwith "library implementation error: they types must match when paired with identity" - - if first.IsIdentity then castToTV second - elif second.IsIdentity then castToTV first - else upcast ComposedFactory(first, second) + upcast ComposedFactory(first, second) and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () @@ -540,10 +545,9 @@ namespace Microsoft.FSharp.Collections and IdentityFactory<'T> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Identity (next) - override __.IsIdentity = true - - static member IdentityFactory = IdentityFactory<'T>() + static let singleton = IdentityFactory<'T>() + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = next + static member IdentityFactory = singleton and MapFactory<'T,'U> (map:'T->'U) = inherit SeqComponentFactory<'T,'U> () @@ -680,12 +684,6 @@ namespace Microsoft.FSharp.Collections else false - and Identity<'T,'V> (next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - Helpers.avoidTailCall (next.ProcessNext input) - and Map<'T,'U,'V> (map:'T->'U, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'T,'V>(next) @@ -937,6 +935,11 @@ namespace Microsoft.FSharp.Collections result.Current <- input true + type Pipeline() = + let mutable halted = false + interface ISeqPipeline with member x.StopFurtherProcessing() = halted <- true + member __.Halted = halted + module Enumerable = [] type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ISeqComponent) = @@ -1005,6 +1008,10 @@ namespace Microsoft.FSharp.Collections and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqComponentFactory<'T,'U>) = inherit EnumerableBase<'U>() + static let iterate (enumerator:IEnumerator<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + while (not pipeline.Halted) && (enumerator.MoveNext ()) do + consumer.ProcessNext enumerator.Current |> ignore + interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1014,20 +1021,16 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let mutable halted = false - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline() let result = f pipeline let consumer = current.Create pipeline result - use enumerator = enumerable.GetEnumerator () - while (not halted) && (enumerator.MoveNext ()) do - consumer.ProcessNext enumerator.Current |> ignore - - (Helpers.upcastISeqComponent consumer).OnComplete () - - result + try + iterate enumerator pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () and AppendEnumerator<'T> (sources:list>) = let sources = sources |> List.rev @@ -1069,6 +1072,10 @@ namespace Microsoft.FSharp.Collections and AppendEnumerable<'T> (sources:list>) = inherit EnumerableBase<'T>() + static let iterate (enumerator:IEnumerator<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + while (not pipeline.Halted) && (enumerator.MoveNext ()) do + consumer.ProcessNext enumerator.Current |> ignore + interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = Helpers.upcastEnumerator (new AppendEnumerator<_> (sources)) @@ -1080,22 +1087,17 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = - let mutable halted = false - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline() let result = f pipeline let consumer : SeqConsumer<'T,'T> = upcast result - let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) use enumerator = enumerable.GetEnumerator () - - while enumerator.MoveNext () do - consumer.ProcessNext enumerator.Current |> ignore - - (Helpers.upcastISeqComponent consumer).OnComplete () - - result + try + iterate enumerator pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () let create enumerable current = Helpers.upcastEnumerable (Enumerable(enumerable, current)) @@ -1135,6 +1137,12 @@ namespace Microsoft.FSharp.Collections type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() + static let iterate (array:array<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let mutable idx = 0 + while (not pipeline.Halted) && (idx < array.Length) do + consumer.ProcessNext array.[idx] |> ignore + idx <- idx + 1 + interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1144,23 +1152,15 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let mutable idx = 0 - let mutable halted = false - - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline () let result = f pipeline let consumer = current.Create pipeline result - - let array = delayedArray () - while (not halted) && (idx < array.Length) do - consumer.ProcessNext array.[idx] |> ignore - idx <- idx + 1 - - (Helpers.upcastISeqComponent consumer).OnComplete () - - result + try + iterate (delayedArray ()) pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () let createDelayed (delayedArray:unit->array<'T>) (current:SeqComponentFactory<'T,'U>) = Helpers.upcastEnumerable (Enumerable(delayedArray, current)) @@ -1198,6 +1198,16 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext list + let iterate (alist:list<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let rec iterate lst = + match pipeline.Halted, lst with + | true, _ + | false, [] -> () + | false, hd :: tl -> + consumer.ProcessNext hd |> ignore + iterate tl + iterate alist + type Enumerable<'T,'U>(alist:list<'T>, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() @@ -1210,24 +1220,15 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let mutable halted = false - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline () let result = f pipeline let consumer = current.Create pipeline result - - let rec iterate lst = - match halted, lst with - | true, _ - | false, [] -> (Helpers.upcastISeqComponent consumer).OnComplete () - | false, hd :: tl -> - consumer.ProcessNext hd |> ignore - iterate tl - - iterate alist - - result + try + iterate alist pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () let create alist current = Helpers.upcastEnumerable (Enumerable(alist, current)) @@ -1256,6 +1257,17 @@ namespace Microsoft.FSharp.Collections type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() + static let iterate (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let rec iterate current = + match pipeline.Halted, generator current with + | true, _ + | false, None -> () + | false, Some (item, next) -> + consumer.ProcessNext item |> ignore + iterate next + + iterate state + interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1265,24 +1277,15 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let mutable halted = false - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline () let result = f pipeline let consumer = current.Create pipeline result - - let rec iterate current = - match halted, generator current with - | true, _ - | false, None -> (Helpers.upcastISeqComponent consumer).OnComplete () - | false, Some (item, next) -> - consumer.ProcessNext item |> ignore - iterate next - - iterate state - - result + try + iterate generator state pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () module Init = // The original implementation of "init" delayed the calculation of Current, and so it was possible @@ -1353,6 +1356,18 @@ namespace Microsoft.FSharp.Collections type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() + static let iterate f (terminatingIdx:int) (isSkipping) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let mutable idx = -1 + let mutable maybeSkipping = true + while (not pipeline.Halted) && (idx < terminatingIdx) do + if maybeSkipping then + maybeSkipping <- isSkipping () + + if (not maybeSkipping) then + consumer.ProcessNext (f (idx+1)) |> ignore + + idx <- idx + 1 + interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1362,33 +1377,17 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) override this.ForEach (createResult:ISeqPipeline->#SeqConsumer<'U,'U>) = - let mutable halted = false - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline () let result = createResult pipeline let consumer = current.Create pipeline result - - let mutable idx = -1 let terminatingIdx = getTerminatingIdx count - - let isSkipping = - makeIsSkipping consumer - - let mutable maybeSkipping = true - - while (not halted) && (idx < terminatingIdx) do - if maybeSkipping then - maybeSkipping <- isSkipping () - - if (not maybeSkipping) then - consumer.ProcessNext (f (idx+1)) |> ignore - - idx <- idx + 1 - - (Helpers.upcastISeqComponent consumer).OnComplete () - - result + let isSkipping = makeIsSkipping consumer + try + iterate f terminatingIdx isSkipping pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () let upto lastOption f = match lastOption with @@ -1443,6 +1442,10 @@ namespace Microsoft.FSharp.Collections type EnumerableDecider<'T>(count:Nullable, f:int->'T) = inherit Enumerable.EnumerableBase<'T>() + static let iterate (enumerator:IEnumerator<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'T>) = + while (not pipeline.Halted) && (enumerator.MoveNext ()) do + consumer.ProcessNext enumerator.Current |> ignore + interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = // we defer back to the original implementation as, as it's quite idiomatic in it's decision @@ -1454,21 +1457,16 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = - let mutable halted = false - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline () let result = f pipeline let consumer : SeqConsumer<'T,'T> = upcast result - use enumerator = (Helpers.upcastEnumerable this).GetEnumerator () - - while enumerator.MoveNext () do - consumer.ProcessNext enumerator.Current |> ignore - - (Helpers.upcastISeqComponent consumer).OnComplete () - - result + try + iterate enumerator pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions @@ -2175,11 +2173,13 @@ namespace Microsoft.FSharp.Collections let toComposer (source:seq<'T>): SeqComposer.SeqEnumerable<'T> = checkNonNull "source" source match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(s, SeqComposer.IdentityFactory.IdentityFactory) + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> upcast s | :? array<'T> as a -> upcast SeqComposer.Array.Enumerable((fun () -> a), SeqComposer.IdentityFactory.IdentityFactory) | :? list<'T> as a -> upcast SeqComposer.List.Enumerable(a, SeqComposer.IdentityFactory.IdentityFactory) | _ -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(source, SeqComposer.IdentityFactory.IdentityFactory) + let inline foreach f (source:SeqComposer.SeqEnumerable<_>) = source.ForEach f + [] let inline sum (source:seq<'a>) : 'a = let composedSource = toComposer source @@ -2204,22 +2204,22 @@ namespace Microsoft.FSharp.Collections [] let inline average (source: seq< ^a>) : ^a = - let composedSource = toComposer source - - let mutable count = 0 let total = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with + source + |> toComposer + |> foreach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'a, SeqComposer.MutableData<'a, int>> (SeqComposer.MutableData(LanguagePrimitives.GenericZero, 0)) with override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator value - count <- count + 1 + this.Accumulator._1 <- Checked.(+) this.Accumulator._1 value + this.Accumulator._2 <- this.Accumulator._2 + 1 true + interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if count = 0 then + member this.OnComplete() = + if (this:?>SeqComposer.AccumulatingConsumer<'a, SeqComposer.MutableData<'a, int>>).Accumulator._2 = 0 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) - LanguagePrimitives.DivideByInt< ^a> total.Accumulator count + LanguagePrimitives.DivideByInt< ^a> total.Accumulator._1 total.Accumulator._2 [] let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index cdcd83cd3a9..27f20260f61 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -27,12 +27,21 @@ namespace Microsoft.FSharp.Collections abstract ProcessNext : input:'T -> bool interface ISeqComponent + [] + type MutableData<'a,'b> = + struct + new : a:'a * b:'b -> MutableData<'a,'b> + val mutable _1: 'a + val mutable _2: 'b + end + [] type AccumulatingConsumer<'T,'U> = + class inherit SeqConsumer<'T,'T> new : initialState:'U -> AccumulatingConsumer<'T,'U> - member Accumulator : 'U - member Accumulator : 'U with set + val mutable Accumulator: 'U + end [] type SeqEnumerable<'T> = From f5918c1fb66f79dbfcb25181c16249d329c7efa7 Mon Sep 17 00:00:00 2001 From: liboz Date: Thu, 20 Oct 2016 13:24:44 +0200 Subject: [PATCH 18/59] Seq.iteri, exists, contains, forall, trypick, pick, tryfind, find, reduce, last, trylast cleanup for Seq.iter, fold Also moves the functions in the seq.fsi file to be alphabetical passing false on process next when ending. fix bug where unfold did not respect the Halted state on Result --- src/fsharp/FSharp.Core/seq.fs | 247 +++++++++++++++++++-------------- src/fsharp/FSharp.Core/seq.fsi | 20 +-- 2 files changed, 155 insertions(+), 112 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index eff58cc5ac5..620f1f9d5ec 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -1240,9 +1240,10 @@ namespace Microsoft.FSharp.Collections let mutable current = state let rec moveNext () = - match generator current with - | None -> false - | Some (item, nextState) -> + match signal.Halted, generator current with + | true, _ + | false, None -> false + | false, Some (item, nextState) -> current <- nextState if seqComponent.ProcessNext item then true @@ -1477,6 +1478,17 @@ namespace Microsoft.FSharp.Collections let mkDelayedSeq (f: unit -> IEnumerable<'T>) = mkSeq (fun () -> f().GetEnumerator()) let inline indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) + + [] + let toComposer (source:seq<'T>): SeqComposer.SeqEnumerable<'T> = + checkNonNull "source" source + match source with + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> upcast s + | :? array<'T> as a -> upcast SeqComposer.Array.Enumerable((fun () -> a), SeqComposer.IdentityFactory.IdentityFactory) + | :? list<'T> as a -> upcast SeqComposer.List.Enumerable(a, SeqComposer.IdentityFactory.IdentityFactory) + | _ -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(source, SeqComposer.IdentityFactory.IdentityFactory) + + let inline foreach f (source:SeqComposer.SeqEnumerable<_>) = source.ForEach f [] let delay f = mkDelayedSeq f @@ -1500,17 +1512,13 @@ namespace Microsoft.FSharp.Collections [] let iter f (source : seq<'T>) = - checkNonNull "source" source - match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> - s.ForEach (fun _ -> + source + |> toComposer + |> foreach (fun _ -> { new SeqComposer.SeqConsumer<'T,'T> () with override this.ProcessNext value = - f value; true }) |> ignore - | _ -> - use e = source.GetEnumerator() - while e.MoveNext() do - f e.Current + f value; true }) + |> ignore [] let item i (source : seq<'T>) = @@ -1531,41 +1539,69 @@ namespace Microsoft.FSharp.Collections [] let iteri f (source : seq<'T>) = - checkNonNull "source" source - use e = source.GetEnumerator() + let composedSource = toComposer source + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) let mutable i = 0 - while e.MoveNext() do - f.Invoke(i, e.Current) - i <- i + 1 + + composedSource.ForEach (fun _ -> + { new SeqComposer.SeqConsumer<'T,'T> () with + override this.ProcessNext value = + f.Invoke(i, value) + i <- i + 1 + true }) + |> ignore [] let exists f (source : seq<'T>) = - checkNonNull "source" source - use e = source.GetEnumerator() - let mutable state = false - while (not state && e.MoveNext()) do - state <- f e.Current - state + let exists = + source + |> toComposer + |> foreach (fun pipeline -> + { new SeqComposer.AccumulatingConsumer<'T, bool> (false) with + override this.ProcessNext value = + if this.Accumulator then + pipeline.StopFurtherProcessing() + false + else + this.Accumulator <- f value + true + }) + exists.Accumulator [] let inline contains element (source : seq<'T>) = - checkNonNull "source" source - use e = source.GetEnumerator() - let mutable state = false - while (not state && e.MoveNext()) do - state <- element = e.Current - state + let contains = + source + |> toComposer + |> foreach (fun pipeline -> + { new SeqComposer.AccumulatingConsumer<'T, bool> (false) with + override this.ProcessNext value = + if this.Accumulator then + pipeline.StopFurtherProcessing() + false + else + this.Accumulator <- element = value + true + }) + contains.Accumulator [] let forall f (source : seq<'T>) = - checkNonNull "source" source - use e = source.GetEnumerator() - let mutable state = true - while (state && e.MoveNext()) do - state <- f e.Current - state - + let forall = + source + |> toComposer + |> foreach (fun pipeline -> + { new SeqComposer.AccumulatingConsumer<'T, bool> (true) with + override this.ProcessNext value = + if this.Accumulator then + this.Accumulator <- f value + false + else + pipeline.StopFurtherProcessing() + true + }) + forall.Accumulator [] let iter2 f (source1 : seq<_>) (source2 : seq<_>) = @@ -1660,33 +1696,47 @@ namespace Microsoft.FSharp.Collections [] let tryPick f (source : seq<'T>) = - checkNonNull "source" source - use e = source.GetEnumerator() - let mutable res = None - while (Option.isNone res && e.MoveNext()) do - res <- f e.Current - res + let pick = + source + |> toComposer + |> foreach (fun pipeline -> + { new SeqComposer.AccumulatingConsumer<'T, Option<'U>> (None) with + override this.ProcessNext value = + if this.Accumulator.IsNone then + this.Accumulator <- f value + true + else + pipeline.StopFurtherProcessing() + false + }) + pick.Accumulator [] let pick f source = - checkNonNull "source" source match tryPick f source with | None -> indexNotFound() | Some x -> x [] let tryFind f (source : seq<'T>) = - checkNonNull "source" source - use e = source.GetEnumerator() - let mutable res = None - while (Option.isNone res && e.MoveNext()) do - let c = e.Current - if f c then res <- Some(c) - res + let find = + source + |> toComposer + |> foreach (fun pipeline -> + { new SeqComposer.AccumulatingConsumer<'T, Option<'T>> (None) with + override this.ProcessNext value = + if this.Accumulator.IsNone then + if f value then + this.Accumulator <- Some(value) + true + else + pipeline.StopFurtherProcessing() + false + }) + find.Accumulator [] let find f source = - checkNonNull "source" source match tryFind f source with | None -> indexNotFound() | Some x -> x @@ -1731,24 +1781,15 @@ namespace Microsoft.FSharp.Collections [] let fold<'T,'State> f (x:'State) (source:seq<'T>) = - checkNonNull "source" source - match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let total = - s.ForEach (fun _ -> + let composedSource = toComposer source + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) + + let total = composedSource.ForEach (fun _ -> { new SeqComposer.AccumulatingConsumer<'T,'State> (x) with override this.ProcessNext value = this.Accumulator <- f.Invoke (this.Accumulator, value) true }) - total.Accumulator - | _ -> - use e = source.GetEnumerator() - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let mutable state = x - while e.MoveNext() do - state <- f.Invoke(state, e.Current) - state + total.Accumulator [] let fold2<'T1,'T2,'State> f (state:'State) (source1: seq<'T1>) (source2: seq<'T2>) = @@ -1768,14 +1809,25 @@ namespace Microsoft.FSharp.Collections [] let reduce f (source : seq<'T>) = - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + let composedSource = toComposer source let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let mutable state = e.Current - while e.MoveNext() do - state <- f.Invoke(state, e.Current) - state + let mutable first = true + + let total = composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + if first then + first <- false + this.Accumulator <- value + else + this.Accumulator <- f.Invoke (this.Accumulator, value) + true + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + total.Accumulator [] let replicate count x = @@ -2169,17 +2221,6 @@ namespace Microsoft.FSharp.Collections then mkDelayedSeq (fun () -> countByValueType keyf source) else mkDelayedSeq (fun () -> countByRefType keyf source) - [] - let toComposer (source:seq<'T>): SeqComposer.SeqEnumerable<'T> = - checkNonNull "source" source - match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> upcast s - | :? array<'T> as a -> upcast SeqComposer.Array.Enumerable((fun () -> a), SeqComposer.IdentityFactory.IdentityFactory) - | :? list<'T> as a -> upcast SeqComposer.List.Enumerable(a, SeqComposer.IdentityFactory.IdentityFactory) - | _ -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(source, SeqComposer.IdentityFactory.IdentityFactory) - - let inline foreach f (source:SeqComposer.SeqEnumerable<_>) = source.ForEach f - [] let inline sum (source:seq<'a>) : 'a = let composedSource = toComposer source @@ -2427,28 +2468,30 @@ namespace Microsoft.FSharp.Collections [] let tail (source: seq<'T>) = source |> seqFactory (SeqComposer.TailFactory ()) - - [] - let last (source : seq<_>) = - checkNonNull "source" source - use e = source.GetEnumerator() - if e.MoveNext() then - let mutable res = e.Current - while (e.MoveNext()) do res <- e.Current - res - else - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - + [] let tryLast (source : seq<_>) = - checkNonNull "source" source - use e = source.GetEnumerator() - if e.MoveNext() then - let mutable res = e.Current - while (e.MoveNext()) do res <- e.Current - Some res - else + let composedSource = toComposer source + let mutable first = true + + let last = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T, 'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + if first then + first <- false + this.Accumulator <- value + true }) + if first then None + else + Some(last.Accumulator) + + [] + let last (source : seq<_>) = + match tryLast source with + | None -> invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + | Some x -> x [] let exactlyOne (source : seq<_>) = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index 27f20260f61..1baeec4685e 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -1155,16 +1155,6 @@ namespace Microsoft.FSharp.Collections [] val inline sortByDescending : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> when 'Key : comparison - /// Builds an SeqEnumerable from the given collection. - /// - /// The input sequence. - /// - /// The result SeqEnumerable. - /// - /// Thrown when the input sequence is null. - [] - val toComposer : source:seq<'T> -> SeqComposer.SeqEnumerable<'T> - /// Returns the sum of the elements in the sequence. /// /// The elements are summed using the + operator and Zero property associated with the generated type. @@ -1239,6 +1229,16 @@ namespace Microsoft.FSharp.Collections /// Thrown when the input sequence is null. [] val toArray: source:seq<'T> -> 'T[] + + /// Builds an SeqEnumerable from the given collection. + /// + /// The input sequence. + /// + /// The result SeqEnumerable. + /// + /// Thrown when the input sequence is null. + [] + val toComposer : source:seq<'T> -> SeqComposer.SeqEnumerable<'T> /// Builds a list from the given collection. /// From 67abac10bf7bbc79cbe3282b1cafcefdfd37191f Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Fri, 21 Oct 2016 04:36:33 +0200 Subject: [PATCH 19/59] Made names a little less verbose Fixed tryPick Processed 1 past the end of the data, as demo'd here: seq { for i = 1 to 5 do yield i failwith "boom" } |> Seq.pick (fun x -> if x = 5 then Some true else None) |> fun result -> assert result Fixed tryFind, similar to tryPick Error seen with seq { for i = 1 to 5 do yield i failwith "boom" } |> Seq.find (fun x -> x = 5) |> fun result -> assert (result=5) cleaned up math functions Just fixing some more one past the end more consistency more consistency foreach now takes seq and calls toComposer Made ignoring return value a bit more explicit processNextInForeach was a bit verbose Consolidated ForEach functionality Seq.concat --- src/fsharp/FSharp.Core/seq.fs | 760 +++++++++++++++------------------ src/fsharp/FSharp.Core/seq.fsi | 19 +- 2 files changed, 365 insertions(+), 414 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 620f1f9d5ec..098a80f5a45 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -165,7 +165,7 @@ namespace Microsoft.FSharp.Core.CompilerServices member x.GetEnumerator() = f() interface IEnumerable with member x.GetEnumerator() = (f() :> IEnumerator) } - + [] type EmptyEnumerable<'T> = | EmptyEnumerable @@ -467,7 +467,7 @@ namespace Microsoft.FSharp.Collections member __.OnDispose() = () [] - type MutableData<'a,'b> = + type Values<'a,'b> = val mutable _1 : 'a val mutable _2 : 'b @@ -476,15 +476,27 @@ namespace Microsoft.FSharp.Collections _2 = b } + [] + type Values<'a,'b,'c> = + val mutable _1 : 'a + val mutable _2 : 'b + val mutable _3 : 'c + + new (a:'a, b:'b, c:'c) = { + _1 = a + _2 = b + _3 = c + } + [] - type AccumulatingConsumer<'T, 'U> = + type Folder<'T, 'U> = inherit SeqConsumer<'T,'T> - val mutable Accumulator : 'U + val mutable Value : 'U - new (initialState) = { + new (init) = { inherit SeqConsumer<'T,'T>() - Accumulator = initialState + Value = init } [] @@ -940,7 +952,84 @@ namespace Microsoft.FSharp.Collections interface ISeqPipeline with member x.StopFurtherProcessing() = halted <- true member __.Halted = halted + module ForEach = + let enumerable (enumerable:IEnumerable<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + use enumerator = enumerable.GetEnumerator () + while (not pipeline.Halted) && (enumerator.MoveNext ()) do + consumer.ProcessNext enumerator.Current |> ignore + + let array (array:array<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let mutable idx = 0 + while (not pipeline.Halted) && (idx < array.Length) do + consumer.ProcessNext array.[idx] |> ignore + idx <- idx + 1 + + let list (alist:list<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let rec iterate lst = + match pipeline.Halted, lst with + | true, _ + | false, [] -> () + | false, hd :: tl -> + consumer.ProcessNext hd |> ignore + iterate tl + iterate alist + + let unfold (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let rec iterate current = + match pipeline.Halted, generator current with + | true, _ + | false, None -> () + | false, Some (item, next) -> + consumer.ProcessNext item |> ignore + iterate next + + iterate state + + let makeIsSkipping (consumer:SeqConsumer<'T,'U>) = + match consumer with + | :? SeqComponent<'T,'U> as c -> c.Skipping + | _ -> fun () -> false + + let init f (terminatingIdx:int) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let mutable idx = -1 + let isSkipping = makeIsSkipping consumer + let mutable maybeSkipping = true + while (not pipeline.Halted) && (idx < terminatingIdx) do + if maybeSkipping then + maybeSkipping <- isSkipping () + + if (not maybeSkipping) then + consumer.ProcessNext (f (idx+1)) |> ignore + + idx <- idx + 1 + + let execute (f:ISeqPipeline->#SeqConsumer<'U,'U>) (current:SeqComponentFactory<'T,'U>) executeOn = + let pipeline = Pipeline() + let result = f pipeline + let consumer = current.Create pipeline result + try + executeOn pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () + module Enumerable = + type Empty<'T>() = + let current () = failwith "library implementation error: Current should never be called" + interface IEnumerator<'T> with + member __.Current = current () + interface IEnumerator with + member __.Current = current () + member __.MoveNext () = false + member __.Reset (): unit = noReset () + interface IDisposable with + member __.Dispose () = () + + type EmptyEnumerators<'T>() = + static let element : IEnumerator<'T> = upcast (new Empty<'T> ()) + static member Element = element + [] type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ISeqComponent) = interface IDisposable with @@ -1008,10 +1097,6 @@ namespace Microsoft.FSharp.Collections and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqComponentFactory<'T,'U>) = inherit EnumerableBase<'U>() - static let iterate (enumerator:IEnumerator<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = - while (not pipeline.Halted) && (enumerator.MoveNext ()) do - consumer.ProcessNext enumerator.Current |> ignore - interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1021,35 +1106,27 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let pipeline = Pipeline() - let result = f pipeline - let consumer = current.Create pipeline result - use enumerator = enumerable.GetEnumerator () - try - iterate enumerator pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () - - and AppendEnumerator<'T> (sources:list>) = - let sources = sources |> List.rev + ForEach.execute f current (ForEach.enumerable enumerable) + and ConcatEnumerator<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = let mutable state = SeqProcessNextStates.NotStarted - let mutable remaining = sources.Tail - let mutable active = sources.Head.GetEnumerator () + let main = sources.GetEnumerator () + + let mutable active = + if main.MoveNext () + then main.Current.GetEnumerator () + else EmptyEnumerators.Element let rec moveNext () = - if active.MoveNext () then true + if active.MoveNext () then + true + elif main.MoveNext () then + active.Dispose () + active <- main.Current.GetEnumerator () + moveNext () else - match remaining with - | [] -> false - | hd :: tl -> - active.Dispose () - active <- hd.GetEnumerator () - remaining <- tl - - moveNext () + state <- SeqProcessNextStates.Finished + false interface IEnumerator<'T> with member __.Current = @@ -1067,18 +1144,15 @@ namespace Microsoft.FSharp.Collections interface IDisposable with member __.Dispose() = + main.Dispose () active.Dispose () and AppendEnumerable<'T> (sources:list>) = inherit EnumerableBase<'T>() - static let iterate (enumerator:IEnumerator<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = - while (not pipeline.Halted) && (enumerator.MoveNext ()) do - consumer.ProcessNext enumerator.Current |> ignore - interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = - Helpers.upcastEnumerator (new AppendEnumerator<_> (sources)) + Helpers.upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = Helpers.upcastEnumerable (Enumerable<'T,'V>(this, next)) @@ -1087,17 +1161,20 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = - let pipeline = Pipeline() - let result = f pipeline - let consumer : SeqConsumer<'T,'T> = upcast result - let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) - use enumerator = enumerable.GetEnumerator () - try - iterate enumerator pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () + ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable this) + + and ConcatEnumerable<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = + inherit EnumerableBase<'T>() + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = + Helpers.upcastEnumerator (new ConcatEnumerator<_,_> (sources)) + + override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = + Helpers.upcastEnumerable (Enumerable<'T,'V>(this, next)) + + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = + ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable this) let create enumerable current = Helpers.upcastEnumerable (Enumerable(enumerable, current)) @@ -1137,12 +1214,6 @@ namespace Microsoft.FSharp.Collections type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() - static let iterate (array:array<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = - let mutable idx = 0 - while (not pipeline.Halted) && (idx < array.Length) do - consumer.ProcessNext array.[idx] |> ignore - idx <- idx + 1 - interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1152,15 +1223,7 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let pipeline = Pipeline () - let result = f pipeline - let consumer = current.Create pipeline result - try - iterate (delayedArray ()) pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () + ForEach.execute f current (ForEach.array (delayedArray ())) let createDelayed (delayedArray:unit->array<'T>) (current:SeqComponentFactory<'T,'U>) = Helpers.upcastEnumerable (Enumerable(delayedArray, current)) @@ -1198,16 +1261,6 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext list - let iterate (alist:list<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = - let rec iterate lst = - match pipeline.Halted, lst with - | true, _ - | false, [] -> () - | false, hd :: tl -> - consumer.ProcessNext hd |> ignore - iterate tl - iterate alist - type Enumerable<'T,'U>(alist:list<'T>, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() @@ -1220,15 +1273,7 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let pipeline = Pipeline () - let result = f pipeline - let consumer = current.Create pipeline result - try - iterate alist pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () + ForEach.execute f current (ForEach.list alist) let create alist current = Helpers.upcastEnumerable (Enumerable(alist, current)) @@ -1258,17 +1303,6 @@ namespace Microsoft.FSharp.Collections type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() - static let iterate (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = - let rec iterate current = - match pipeline.Halted, generator current with - | true, _ - | false, None -> () - | false, Some (item, next) -> - consumer.ProcessNext item |> ignore - iterate next - - iterate state - interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1278,15 +1312,7 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let pipeline = Pipeline () - let result = f pipeline - let consumer = current.Create pipeline result - try - iterate generator state pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () + ForEach.execute f current (ForEach.unfold generator state) module Init = // The original implementation of "init" delayed the calculation of Current, and so it was possible @@ -1310,16 +1336,11 @@ namespace Microsoft.FSharp.Collections else System.Int32.MaxValue - let makeIsSkipping (consumer:SeqConsumer<'T,'U>) = - match consumer with - | :? SeqComponent<'T,'U> as c -> c.Skipping - | _ -> fun () -> false - type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:SeqConsumer<'T,'U>, signal:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) let isSkipping = - makeIsSkipping seqComponent + ForEach.makeIsSkipping seqComponent let terminatingIdx = getTerminatingIdx count @@ -1357,18 +1378,6 @@ namespace Microsoft.FSharp.Collections type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() - static let iterate f (terminatingIdx:int) (isSkipping) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = - let mutable idx = -1 - let mutable maybeSkipping = true - while (not pipeline.Halted) && (idx < terminatingIdx) do - if maybeSkipping then - maybeSkipping <- isSkipping () - - if (not maybeSkipping) then - consumer.ProcessNext (f (idx+1)) |> ignore - - idx <- idx + 1 - interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1378,17 +1387,8 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) override this.ForEach (createResult:ISeqPipeline->#SeqConsumer<'U,'U>) = - let pipeline = Pipeline () - let result = createResult pipeline - let consumer = current.Create pipeline result let terminatingIdx = getTerminatingIdx count - let isSkipping = makeIsSkipping consumer - try - iterate f terminatingIdx isSkipping pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () + ForEach.execute createResult current (ForEach.init f terminatingIdx) let upto lastOption f = match lastOption with @@ -1443,10 +1443,6 @@ namespace Microsoft.FSharp.Collections type EnumerableDecider<'T>(count:Nullable, f:int->'T) = inherit Enumerable.EnumerableBase<'T>() - static let iterate (enumerator:IEnumerator<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'T>) = - while (not pipeline.Halted) && (enumerator.MoveNext ()) do - consumer.ProcessNext enumerator.Current |> ignore - interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = // we defer back to the original implementation as, as it's quite idiomatic in it's decision @@ -1458,16 +1454,7 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = - let pipeline = Pipeline () - let result = f pipeline - let consumer : SeqConsumer<'T,'T> = upcast result - use enumerator = (Helpers.upcastEnumerable this).GetEnumerator () - try - iterate enumerator pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () + ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable (Helpers.upcastEnumerable this)) #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions @@ -1488,7 +1475,10 @@ namespace Microsoft.FSharp.Collections | :? list<'T> as a -> upcast SeqComposer.List.Enumerable(a, SeqComposer.IdentityFactory.IdentityFactory) | _ -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(source, SeqComposer.IdentityFactory.IdentityFactory) - let inline foreach f (source:SeqComposer.SeqEnumerable<_>) = source.ForEach f + let inline foreach f (source:seq<_>) = + source + |> toComposer + |> fun composer -> composer.ForEach f [] let delay f = mkDelayedSeq f @@ -1513,11 +1503,11 @@ namespace Microsoft.FSharp.Collections [] let iter f (source : seq<'T>) = source - |> toComposer |> foreach (fun _ -> { new SeqComposer.SeqConsumer<'T,'T> () with override this.ProcessNext value = - f value; true }) + f value + Unchecked.defaultof }) |> ignore [] @@ -1539,69 +1529,54 @@ namespace Microsoft.FSharp.Collections [] let iteri f (source : seq<'T>) = - let composedSource = toComposer source - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let mutable i = 0 - - composedSource.ForEach (fun _ -> - { new SeqComposer.SeqConsumer<'T,'T> () with - override this.ProcessNext value = - f.Invoke(i, value) - i <- i + 1 - true }) + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T, int> (0) with + override this.ProcessNext value = + f.Invoke(this.Value, value) + this.Value <- this.Value + 1 + Unchecked.defaultof }) |> ignore [] let exists f (source : seq<'T>) = - let exists = - source - |> toComposer - |> foreach (fun pipeline -> - { new SeqComposer.AccumulatingConsumer<'T, bool> (false) with - override this.ProcessNext value = - if this.Accumulator then - pipeline.StopFurtherProcessing() - false - else - this.Accumulator <- f value - true - }) - exists.Accumulator + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, bool> (false) with + override this.ProcessNext value = + if f value then + this.Value <- true + pipeline.StopFurtherProcessing () + Unchecked.defaultof + }) + |> fun exists -> exists.Value [] let inline contains element (source : seq<'T>) = - let contains = - source - |> toComposer - |> foreach (fun pipeline -> - { new SeqComposer.AccumulatingConsumer<'T, bool> (false) with - override this.ProcessNext value = - if this.Accumulator then - pipeline.StopFurtherProcessing() - false - else - this.Accumulator <- element = value - true - }) - contains.Accumulator + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, bool> (false) with + override this.ProcessNext value = + if element = value then + this.Value <- true + pipeline.StopFurtherProcessing() + Unchecked.defaultof + }) + |> fun contains -> contains.Value [] let forall f (source : seq<'T>) = - let forall = - source - |> toComposer - |> foreach (fun pipeline -> - { new SeqComposer.AccumulatingConsumer<'T, bool> (true) with - override this.ProcessNext value = - if this.Accumulator then - this.Accumulator <- f value - false - else - pipeline.StopFurtherProcessing() - true - }) - forall.Accumulator + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, bool> (true) with + override this.ProcessNext value = + if not (f value) then + this.Value <- false + pipeline.StopFurtherProcessing() + Unchecked.defaultof + }) + |> fun forall -> forall.Value [] let iter2 f (source1 : seq<_>) (source2 : seq<_>) = @@ -1696,20 +1671,17 @@ namespace Microsoft.FSharp.Collections [] let tryPick f (source : seq<'T>) = - let pick = - source - |> toComposer - |> foreach (fun pipeline -> - { new SeqComposer.AccumulatingConsumer<'T, Option<'U>> (None) with - override this.ProcessNext value = - if this.Accumulator.IsNone then - this.Accumulator <- f value - true - else - pipeline.StopFurtherProcessing() - false - }) - pick.Accumulator + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, Option<'U>> (None) with + override this.ProcessNext value = + match f value with + | (Some _) as some -> + this.Value <- some + pipeline.StopFurtherProcessing() + | None -> () + Unchecked.defaultof }) + |> fun pick -> pick.Value [] let pick f source = @@ -1719,21 +1691,15 @@ namespace Microsoft.FSharp.Collections [] let tryFind f (source : seq<'T>) = - let find = - source - |> toComposer - |> foreach (fun pipeline -> - { new SeqComposer.AccumulatingConsumer<'T, Option<'T>> (None) with - override this.ProcessNext value = - if this.Accumulator.IsNone then - if f value then - this.Accumulator <- Some(value) - true - else - pipeline.StopFurtherProcessing() - false - }) - find.Accumulator + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, Option<'T>> (None) with + override this.ProcessNext value = + if f value then + this.Value <- Some value + pipeline.StopFurtherProcessing() + Unchecked.defaultof }) + |> fun find -> find.Value [] let find f source = @@ -1759,11 +1725,10 @@ namespace Microsoft.FSharp.Collections use ie = source.GetEnumerator() not (ie.MoveNext()) - [] - let concat sources = + let concat (sources:seq<#seq<'T>>) : seq<'T> = checkNonNull "sources" sources - mkConcatSeq sources + upcast SeqComposer.Enumerable.ConcatEnumerable sources [] let length (source : seq<'T>) = @@ -1781,15 +1746,15 @@ namespace Microsoft.FSharp.Collections [] let fold<'T,'State> f (x:'State) (source:seq<'T>) = - let composedSource = toComposer source let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let total = composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'State> (x) with - override this.ProcessNext value = - this.Accumulator <- f.Invoke (this.Accumulator, value) - true }) - total.Accumulator + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,'State> (x) with + override this.ProcessNext value = + this.Value <- f.Invoke (this.Value, value) + Unchecked.defaultof }) + |> fun folded -> folded.Value [] let fold2<'T1,'T2,'State> f (state:'State) (source1: seq<'T1>) (source2: seq<'T2>) = @@ -1809,25 +1774,25 @@ namespace Microsoft.FSharp.Collections [] let reduce f (source : seq<'T>) = - let composedSource = toComposer source let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let mutable first = true - - let total = composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = - if first then - first <- false - this.Accumulator <- value - else - this.Accumulator <- f.Invoke (this.Accumulator, value) - true - interface SeqComposer.ISeqComponent with - member this.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - total.Accumulator + + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T, SeqComposer.Values> (SeqComposer.Values<_,_>(true, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + else + this.Value._2 <- f.Invoke (this.Value._2, value) + Unchecked.defaultof + + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'T, SeqComposer.Values>).Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun reduced -> reduced.Value._2 [] let replicate count x = @@ -2223,112 +2188,98 @@ namespace Microsoft.FSharp.Collections [] let inline sum (source:seq<'a>) : 'a = - let composedSource = toComposer source - let total = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with - override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator value - true }) - total.Accumulator + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'a,'a> (LanguagePrimitives.GenericZero) with + override this.ProcessNext value = + this.Value <- Checked.(+) this.Value value + Unchecked.defaultof }) + |> fun sum -> sum.Value [] let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U = - let composedSource = toComposer source - let total = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with - override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator (f value) - true }) - total.Accumulator + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + override this.ProcessNext value = + this.Value <- Checked.(+) this.Value (f value) + Unchecked.defaultof }) + |> fun sum -> sum.Value [] let inline average (source: seq< ^a>) : ^a = - let total = - source - |> toComposer - |> foreach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'a, SeqComposer.MutableData<'a, int>> (SeqComposer.MutableData(LanguagePrimitives.GenericZero, 0)) with - override this.ProcessNext value = - this.Accumulator._1 <- Checked.(+) this.Accumulator._1 value - this.Accumulator._2 <- this.Accumulator._2 + 1 - true - - interface SeqComposer.ISeqComponent with - member this.OnComplete() = - if (this:?>SeqComposer.AccumulatingConsumer<'a, SeqComposer.MutableData<'a, int>>).Accumulator._2 = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - LanguagePrimitives.DivideByInt< ^a> total.Accumulator._1 total.Accumulator._2 + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'a, SeqComposer.Values<'a, int>> (SeqComposer.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + override this.ProcessNext value = + this.Value._1 <- Checked.(+) this.Value._1 value + this.Value._2 <- this.Value._2 + 1 + Unchecked.defaultof + + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'a, SeqComposer.Values<'a, int>>).Value._2 = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) + |> fun total -> LanguagePrimitives.DivideByInt< ^a> total.Value._1 total.Value._2 [] let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = - let composedSource = toComposer source - let mutable count = 0 - let total = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with - override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator (f value) - count <- count + 1 - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if count = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - LanguagePrimitives.DivideByInt< ^U> total.Accumulator count + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,SeqComposer.Values<'U, int>> (SeqComposer.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + override this.ProcessNext value = + this.Value._1 <- Checked.(+) this.Value._1 (f value) + this.Value._2 <- this.Value._2 + 1 + Unchecked.defaultof + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'T,SeqComposer.Values<'U, int>>).Value._2 = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) + |> fun total -> LanguagePrimitives.DivideByInt< ^U> total.Value._1 total.Value._2 [] let inline min (source: seq<_>) = - let composedSource = toComposer source - - let mutable first = true - let min = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = - if first then - first <- false - this.Accumulator <- value - elif value < this.Accumulator then - this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - min.Accumulator + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_>(true, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + elif value < this.Value._2 then + this.Value._2 <- value + Unchecked.defaultof + + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun min -> min.Value._2 [] let inline minBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - let composedSource = toComposer source - - let mutable first = true - let mutable acc = Unchecked.defaultof<'U> - let min = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = - let currValue = value - let curr = f currValue - if first then - first <- false - acc <- curr - this.Accumulator <- value - else - if curr < acc then - acc <- curr - this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - min.Accumulator + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + match this.Value._1, f value with + | true, valueU -> + this.Value._1 <- false + this.Value._2 <- valueU + this.Value._3 <- value + | false, valueU when valueU < this.Value._2 -> + this.Value._2 <- valueU + this.Value._3 <- value + | _ -> () + Unchecked.defaultof + + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun min -> min.Value._3 (* [] let inline minValBy (f : 'T -> 'U) (source: seq<'T>) : 'U = @@ -2348,54 +2299,47 @@ namespace Microsoft.FSharp.Collections *) [] let inline max (source: seq<_>) = - let composedSource = toComposer source - - let mutable first = true - let max = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = - if first then - first <- false - this.Accumulator <- value - else - if value > this.Accumulator then - this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - max.Accumulator + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_>(true, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + elif value > this.Value._2 then + this.Value._2 <- value + Unchecked.defaultof + + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun max -> max.Value._2 [] let inline maxBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - let composedSource = toComposer source - - let mutable first = true - let mutable acc = Unchecked.defaultof<'U> - let min = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = - let currValue = value - let curr = f currValue - if first then - first <- false - acc <- curr - this.Accumulator <- value - else - if curr > acc then - acc <- curr - this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - min.Accumulator + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + match this.Value._1, f value with + | true, valueU -> + this.Value._1 <- false + this.Value._2 <- valueU + this.Value._3 <- value + | false, valueU when valueU > this.Value._2 -> + this.Value._2 <- valueU + this.Value._3 <- value + | _ -> () + Unchecked.defaultof + + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun min -> min.Value._3 (* [] @@ -2471,21 +2415,19 @@ namespace Microsoft.FSharp.Collections [] let tryLast (source : seq<_>) = - let composedSource = toComposer source - let mutable first = true - - let last = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T, 'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = - if first then - first <- false - this.Accumulator <- value - true }) - if first then - None - else - Some(last.Accumulator) + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T, SeqComposer.Values> (SeqComposer.Values(true, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + Unchecked.defaultof }) + |> fun tried -> + if tried.Value._1 then + None + else + Some tried.Value._2 [] let last (source : seq<_>) = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index 1baeec4685e..7e94539f3ea 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -28,19 +28,28 @@ namespace Microsoft.FSharp.Collections interface ISeqComponent [] - type MutableData<'a,'b> = + type Values<'a,'b> = struct - new : a:'a * b:'b -> MutableData<'a,'b> + new : a:'a * b:'b -> Values<'a,'b> val mutable _1: 'a val mutable _2: 'b end + [] + type Values<'a,'b,'c> = + struct + new : a:'a * b:'b * c:'c -> Values<'a,'b,'c> + val mutable _1: 'a + val mutable _2: 'b + val mutable _3: 'c + end + [] - type AccumulatingConsumer<'T,'U> = + type Folder<'T,'U> = class inherit SeqConsumer<'T,'T> - new : initialState:'U -> AccumulatingConsumer<'T,'U> - val mutable Accumulator: 'U + new : init:'U -> Folder<'T,'U> + val mutable Value: 'U end [] From 873caa55bbbb1a22506ff6cefbfd9b8af2424f52 Mon Sep 17 00:00:00 2001 From: liboz Date: Sat, 22 Oct 2016 13:29:55 +0200 Subject: [PATCH 20/59] findIndex/tryFindIndex fix bug with Concat when there are side effects --- src/fsharp/FSharp.Core/seq.fs | 46 +++++++++++++++-------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 098a80f5a45..f664605abb2 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -1112,10 +1112,7 @@ namespace Microsoft.FSharp.Collections let mutable state = SeqProcessNextStates.NotStarted let main = sources.GetEnumerator () - let mutable active = - if main.MoveNext () - then main.Current.GetEnumerator () - else EmptyEnumerators.Element + let mutable active = EmptyEnumerators.Element let rec moveNext () = if active.MoveNext () then @@ -1931,31 +1928,26 @@ namespace Microsoft.FSharp.Collections let res = Array.scanSubRight f arr 0 (arr.Length - 1) acc res :> seq<_>) - [] - let findIndex p (source:seq<_>) = - checkNonNull "source" source - use ie = source.GetEnumerator() - let rec loop i = - if ie.MoveNext() then - if p ie.Current then - i - else loop (i+1) - else - indexNotFound() - loop 0 - [] let tryFindIndex p (source:seq<_>) = - checkNonNull "source" source - use ie = source.GetEnumerator() - let rec loop i = - if ie.MoveNext() then - if p ie.Current then - Some i - else loop (i+1) - else - None - loop 0 + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, SeqComposer.Values, int>> (SeqComposer.Values<_,_>(None, 0)) with + override this.ProcessNext value = + if p value then + this.Value._1 <- Some(this.Value._2) + pipeline.StopFurtherProcessing() + else + this.Value._2 <- this.Value._2 + 1 + Unchecked.defaultof + }) + |> fun tried -> tried.Value._1 + + [] + let findIndex p (source:seq<_>) = + match tryFindIndex p source with + | None -> indexNotFound() + | Some x -> x [] let tryFindIndexBack f (source : seq<'T>) = From 5d1d0edcd1e6ef2c6e6f41dd4ac4dc70d3d21f0e Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sun, 23 Oct 2016 19:30:44 +1100 Subject: [PATCH 21/59] Fix a Take bug The following caused an exception, when it shouldn't: [1;2;3] |> Seq.take 100 |> Seq.takeWhile (fun _ -> false) |> Seq.iter (fun _ -> ()) I'm not 100% happy with how I'm allocating ids, nor really with the added ceremony of the solution, but I think the idea of how to resolve is basically the right one. --- src/fsharp/FSharp.Core/seq.fs | 275 ++++++++++++++++----------------- src/fsharp/FSharp.Core/seq.fsi | 4 +- 2 files changed, 139 insertions(+), 140 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index f664605abb2..7503c1f47a5 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -452,18 +452,18 @@ namespace Microsoft.FSharp.Collections open IEnumerator type ISeqComponent = - abstract OnComplete : unit -> unit + abstract OnComplete : int -> unit abstract OnDispose : unit -> unit type ISeqPipeline = - abstract StopFurtherProcessing : unit -> unit + abstract StopFurtherProcessing : int -> unit [] type SeqConsumer<'T,'U> () = abstract ProcessNext : input:'T -> bool interface ISeqComponent with - member __.OnComplete() = () + member __.OnComplete _ = () member __.OnDispose() = () [] @@ -518,133 +518,135 @@ namespace Microsoft.FSharp.Collections let seqComponentTail = { new ISeqComponent with - member __.OnComplete() = () + member __.OnComplete _ = () member __.OnDispose() = () } type [] SeqComponentFactory<'T,'U> () = - abstract Create<'V> : ISeqPipeline -> SeqConsumer<'U,'V> -> SeqConsumer<'T,'V> + abstract Create<'V> : ISeqPipeline -> SeqConsumer<'U,'V> -> haltingIdx:int -> SeqConsumer<'T,'V> and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>) = inherit SeqComponentFactory<'T,'V> () - override __.Create<'W> (result:ISeqPipeline) (next:SeqConsumer<'V,'W>) : SeqConsumer<'T,'W> = - first.Create result (second.Create result next) + override __.Create<'W> (result:ISeqPipeline) (next:SeqConsumer<'V,'W>) (haltingIdx:int) : SeqConsumer<'T,'W> = + first.Create result (second.Create result next (haltingIdx+1)) (haltingIdx+2) static member Combine (first:SeqComponentFactory<'T,'U>) (second:SeqComponentFactory<'U,'V>) : SeqComponentFactory<'T,'V> = upcast ComposedFactory(first, second) and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = upcast Choose (filter, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Choose (filter, next, haltingIdx) and DistinctFactory<'T when 'T: equality> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Distinct (next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Distinct (next, haltingIdx) and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast DistinctBy (keyFunction, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast DistinctBy (keyFunction, next, haltingIdx) and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Except (itemsToExclude, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Except (itemsToExclude, next, haltingIdx) and FilterFactory<'T> (filter:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = match next with - | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter - | _ -> upcast Filter (filter, next) + | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter haltingIdx + | _ -> upcast Filter (filter, next, haltingIdx) and IdentityFactory<'T> () = inherit SeqComponentFactory<'T,'T> () static let singleton = IdentityFactory<'T>() - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = next + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (_haltingIdx:int) : SeqConsumer<'T,'V> = next static member IdentityFactory = singleton and MapFactory<'T,'U> (map:'T->'U) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = match next with - | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map - | _ -> upcast Map<_,_,_> (map, next) + | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map haltingIdx + | _ -> upcast Map<_,_,_> (map, next, haltingIdx) and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'First,'V> = upcast Map2First (map, input2, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'First,'V> = upcast Map2First (map, input2, result, next, haltingIdx) and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = inherit SeqComponentFactory<'Second,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'Second,'V> = upcast Map2Second (map, input1, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'Second,'V> = upcast Map2Second (map, input1, result, next, haltingIdx) and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'First,'V> = upcast Map3 (map, input2, input3, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'First,'V> = upcast Map3 (map, input2, input3, result, next, haltingIdx) and MapiFactory<'T,'U> (mapi:int->'T->'U) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = upcast Mapi (mapi, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Mapi (mapi, next, haltingIdx) and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'First,'V> = upcast Mapi2 (map, input2, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'First,'V> = upcast Mapi2 (map, input2, result, next, haltingIdx) and PairwiseFactory<'T> () = inherit SeqComponentFactory<'T,'T*'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T*'T,'V>) : SeqConsumer<'T,'V> = upcast Pairwise next + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T*'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Pairwise (next, haltingIdx) and SkipFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Skip (count, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Skip (count, next, haltingIdx) and SkipWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast SkipWhile (predicate, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast SkipWhile (predicate, next, haltingIdx) and TakeWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast TakeWhile (predicate, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast TakeWhile (predicate, result, next, haltingIdx) and TakeFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Take (count, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Take (count, result, next, haltingIdx) and TailFactory<'T> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Tail<'T,'V> (next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Tail<'T,'V> (next, haltingIdx) and TruncateFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Truncate (count, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Truncate (count, result, next, haltingIdx) - and [] SeqComponent<'T,'U> (next:ISeqComponent) = + and [] SeqComponent<'T,'U> (next:ISeqComponent, haltingIdx:int) = inherit SeqConsumer<'T,'U>() // Seq.init(Infinite)? lazily uses Current. The only SeqComposer component that can do that is Skip // and it can only do it at the start of a sequence abstract Skipping : unit -> bool - abstract CreateMap<'S> : map:('S->'T) -> SeqComponent<'S,'U> - abstract CreateFilter : filter:('T->bool) -> SeqComponent<'T,'U> + abstract CreateMap<'S> : map:('S->'T) -> haltingIdx:int -> SeqComponent<'S,'U> + abstract CreateFilter : filter:('T->bool) -> haltingIdx:int -> SeqComponent<'T,'U> interface ISeqComponent with - member __.OnComplete () = next.OnComplete () + member __.OnComplete halted = next.OnComplete halted member __.OnDispose () = next.OnDispose () + member __.HaltingIdx = haltingIdx + default __.Skipping () = false - default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) - default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) + default this.CreateMap<'S> (map:'S->'T) (haltingIdx:int) = upcast Map<_,_,_> (map, this, haltingIdx) + default this.CreateFilter (filter:'T->bool) (haltingIdx:int) = upcast Filter (filter, this, haltingIdx) - and Choose<'T,'U,'V> (choose:'T->option<'U>, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) + and Choose<'T,'U,'V> (choose:'T->option<'U>, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) override __.ProcessNext (input:'T) : bool = match choose input with | Some value -> Helpers.avoidTailCall (next.ProcessNext value) | None -> false - and Distinct<'T,'V when 'T: equality> (next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Distinct<'T,'V when 'T: equality> (next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) @@ -654,8 +656,8 @@ namespace Microsoft.FSharp.Collections else false - and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) @@ -665,8 +667,8 @@ namespace Microsoft.FSharp.Collections else false - and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) @@ -676,10 +678,10 @@ namespace Microsoft.FSharp.Collections else false - and Filter<'T,'V> (filter:'T->bool, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Filter<'T,'V> (filter:'T->bool, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) - override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) + override this.CreateMap<'S> (map:'S->'T) (haltingIdx:int) = upcast MapThenFilter<_,_,_> (map, filter, next, haltingIdx) override __.ProcessNext (input:'T) : bool = if filter input then @@ -687,8 +689,8 @@ namespace Microsoft.FSharp.Collections else false - and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) + and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) override __.ProcessNext (input:'T) : bool = if filter input then @@ -696,16 +698,16 @@ namespace Microsoft.FSharp.Collections else false - and Map<'T,'U,'V> (map:'T->'U, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) + and Map<'T,'U,'V> (map:'T->'U, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) - override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) + override this.CreateFilter (filter:'T->bool) (haltingIdx:int) = upcast FilterThenMap (filter, map, next, haltingIdx) override __.ProcessNext (input:'T) : bool = Helpers.avoidTailCall (next.ProcessNext (map input)) - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'First,'V>(next) + and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'First,'V>(next, haltingIdx) let input2 = enumerable2.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map @@ -714,7 +716,7 @@ namespace Microsoft.FSharp.Collections if input2.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) else - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx false interface ISeqComponent with @@ -724,8 +726,8 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'Second,'V>(next) + and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'Second,'V>(next, haltingIdx) let input1 = enumerable1.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map @@ -734,7 +736,7 @@ namespace Microsoft.FSharp.Collections if input1.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) else - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx false interface ISeqComponent with @@ -744,8 +746,8 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'First,'V>(next) + and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'First,'V>(next, haltingIdx) let input2 = enumerable2.GetEnumerator () let input3 = enumerable3.GetEnumerator () @@ -755,7 +757,7 @@ namespace Microsoft.FSharp.Collections if input2.MoveNext () && input3.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) else - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx false interface ISeqComponent with @@ -768,8 +770,8 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) + and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) override __.ProcessNext (input:'T) : bool = let u = map input @@ -778,8 +780,8 @@ namespace Microsoft.FSharp.Collections else false - and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) + and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let mutable idx = 0 let mapi' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt mapi @@ -788,8 +790,8 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) - and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'First,'V>(next) + and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'First,'V>(next, haltingIdx) let mutable idx = 0 let input2 = enumerable2.GetEnumerator () @@ -800,7 +802,7 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) else - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx false interface ISeqComponent with @@ -810,8 +812,8 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and Pairwise<'T,'V> (next:SeqConsumer<'T*'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Pairwise<'T,'V> (next:SeqConsumer<'T*'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let mutable isFirst = true let mutable lastValue = Unchecked.defaultof<'T> @@ -826,8 +828,8 @@ namespace Microsoft.FSharp.Collections lastValue <- input Helpers.avoidTailCall (next.ProcessNext currentPair) - and Skip<'T,'V> (skipCount:int, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Skip<'T,'V> (skipCount:int, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let mutable count = 0 @@ -846,15 +848,15 @@ namespace Microsoft.FSharp.Collections Helpers.avoidTailCall (next.ProcessNext input) interface ISeqComponent with - override __.OnComplete () = + override __.OnComplete halted = if count < skipCount then let x = skipCount - count invalidOpFmt "tried to skip {0} {1} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - (Helpers.upcastISeqComponent next).OnComplete () + (Helpers.upcastISeqComponent next).OnComplete halted - and SkipWhile<'T,'V> (predicate:'T->bool, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and SkipWhile<'T,'V> (predicate:'T->bool, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let mutable skip = true @@ -868,29 +870,29 @@ namespace Microsoft.FSharp.Collections else Helpers.avoidTailCall (next.ProcessNext input) - and Take<'T,'V> (takeCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>) = - inherit Truncate<'T, 'V>(takeCount, result, next) + and Take<'T,'V> (takeCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit Truncate<'T, 'V>(takeCount, result, next, haltingIdx) interface ISeqComponent with - override this.OnComplete () = - if this.Count < takeCount then + override this.OnComplete halted = + if halted = 0 || halted > haltingIdx && this.Count < takeCount then let x = takeCount - this.Count invalidOpFmt "tried to take {0} {1} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - (Helpers.upcastISeqComponent next).OnComplete () + (Helpers.upcastISeqComponent next).OnComplete halted - and TakeWhile<'T,'V> (predicate:'T->bool, result:ISeqPipeline, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and TakeWhile<'T,'V> (predicate:'T->bool, result:ISeqPipeline, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) override __.ProcessNext (input:'T) : bool = if predicate input then Helpers.avoidTailCall (next.ProcessNext input) else - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx false - and Tail<'T, 'V> (next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Tail<'T, 'V> (next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let mutable first = true @@ -902,13 +904,13 @@ namespace Microsoft.FSharp.Collections Helpers.avoidTailCall (next.ProcessNext input) interface ISeqComponent with - override this.OnComplete () = + override this.OnComplete halted = if first then invalidArg "source" (SR.GetString(SR.notEnoughElements)) - (Helpers.upcastISeqComponent next).OnComplete () + (Helpers.upcastISeqComponent next).OnComplete halted - and Truncate<'T,'V> (truncateCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Truncate<'T,'V> (truncateCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let mutable count = 0 @@ -918,10 +920,10 @@ namespace Microsoft.FSharp.Collections if count < truncateCount then count <- count + 1 if count = truncateCount then - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx next.ProcessNext input else - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx false type SeqProcessNextStates = @@ -930,14 +932,14 @@ namespace Microsoft.FSharp.Collections | Finished = 2 type Result<'T>() = - let mutable halted = false + let mutable haltedIdx = 0 member val Current = Unchecked.defaultof<'T> with get, set member val SeqState = SeqProcessNextStates.NotStarted with get, set - member __.Halted = halted + member __.Halted = haltedIdx interface ISeqPipeline with - member __.StopFurtherProcessing () = halted <- true + member __.StopFurtherProcessing haltingIdx = haltedIdx <- haltingIdx // SetResult<> is used at the end of the chain of SeqComponents to assign the final value type SetResult<'T> (result:Result<'T>) = @@ -948,40 +950,38 @@ namespace Microsoft.FSharp.Collections true type Pipeline() = - let mutable halted = false - interface ISeqPipeline with member x.StopFurtherProcessing() = halted <- true + let mutable halted = 0 + interface ISeqPipeline with member x.StopFurtherProcessing haltingIdx = halted <- haltingIdx member __.Halted = halted module ForEach = let enumerable (enumerable:IEnumerable<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = use enumerator = enumerable.GetEnumerator () - while (not pipeline.Halted) && (enumerator.MoveNext ()) do + while (pipeline.Halted = 0) && (enumerator.MoveNext ()) do consumer.ProcessNext enumerator.Current |> ignore let array (array:array<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = let mutable idx = 0 - while (not pipeline.Halted) && (idx < array.Length) do + while (pipeline.Halted = 0) && (idx < array.Length) do consumer.ProcessNext array.[idx] |> ignore idx <- idx + 1 let list (alist:list<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = let rec iterate lst = match pipeline.Halted, lst with - | true, _ - | false, [] -> () - | false, hd :: tl -> + | 0, hd :: tl -> consumer.ProcessNext hd |> ignore iterate tl + | _ -> () iterate alist let unfold (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = let rec iterate current = match pipeline.Halted, generator current with - | true, _ - | false, None -> () - | false, Some (item, next) -> + | 0, Some (item, next) -> consumer.ProcessNext item |> ignore iterate next + | _ -> () iterate state @@ -994,7 +994,7 @@ namespace Microsoft.FSharp.Collections let mutable idx = -1 let isSkipping = makeIsSkipping consumer let mutable maybeSkipping = true - while (not pipeline.Halted) && (idx < terminatingIdx) do + while (pipeline.Halted = 0) && (idx < terminatingIdx) do if maybeSkipping then maybeSkipping <- isSkipping () @@ -1006,10 +1006,10 @@ namespace Microsoft.FSharp.Collections let execute (f:ISeqPipeline->#SeqConsumer<'U,'U>) (current:SeqComponentFactory<'T,'U>) executeOn = let pipeline = Pipeline() let result = f pipeline - let consumer = current.Create pipeline result + let consumer = current.Create pipeline result 1 try executeOn pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () + (Helpers.upcastISeqComponent consumer).OnComplete pipeline.Halted result finally (Helpers.upcastISeqComponent consumer).OnDispose () @@ -1072,14 +1072,14 @@ namespace Microsoft.FSharp.Collections inherit EnumeratorBase<'U>(result, seqComponent) let rec moveNext () = - if (not result.Halted) && source.MoveNext () then + if (result.Halted = 0) && source.MoveNext () then if seqComponent.ProcessNext source.Current then true else moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete () + (Helpers.upcastISeqComponent seqComponent).OnComplete result.Halted false interface IEnumerator with @@ -1100,7 +1100,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (SetResult<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (SetResult<'U> result) 1, result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) @@ -1192,7 +1192,7 @@ namespace Microsoft.FSharp.Collections initMoveNext <- ignore let rec moveNext () = - if (not result.Halted) && idx < array.Length then + if (result.Halted = 0) && idx < array.Length then idx <- idx+1 if seqComponent.ProcessNext array.[idx-1] then true @@ -1200,7 +1200,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete () + (Helpers.upcastISeqComponent seqComponent).OnComplete result.Halted false interface IEnumerator with @@ -1214,7 +1214,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result (SetResult<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result (SetResult<'U> result) 1, result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) @@ -1242,7 +1242,7 @@ namespace Microsoft.FSharp.Collections let rec moveNext current = match result.Halted, current with - | false, head::tail -> + | 0, head::tail -> if seqComponent.ProcessNext head then list <- tail true @@ -1250,7 +1250,7 @@ namespace Microsoft.FSharp.Collections moveNext tail | _ -> result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete () + (Helpers.upcastISeqComponent seqComponent).OnComplete result.Halted false interface IEnumerator with @@ -1264,7 +1264,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (SetResult<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (SetResult<'U> result) 1, result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) @@ -1283,14 +1283,13 @@ namespace Microsoft.FSharp.Collections let rec moveNext () = match signal.Halted, generator current with - | true, _ - | false, None -> false - | false, Some (item, nextState) -> + | 0, Some (item, nextState) -> current <- nextState if seqComponent.ProcessNext item then true else moveNext () + | _ -> false interface IEnumerator with member __.MoveNext () = @@ -1303,7 +1302,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (SetResult<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (SetResult<'U> result) 1, result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) @@ -1346,7 +1345,7 @@ namespace Microsoft.FSharp.Collections let mutable idx = -1 let rec moveNext () = - if (not signal.Halted) && idx < terminatingIdx then + if (signal.Halted = 0) && idx < terminatingIdx then idx <- idx + 1 if maybeSkipping then @@ -1360,11 +1359,11 @@ namespace Microsoft.FSharp.Collections true else moveNext () - elif (not signal.Halted) && idx = System.Int32.MaxValue then + elif (signal.Halted = 0) && idx = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) else signal.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete () + (Helpers.upcastISeqComponent seqComponent).OnComplete signal.Halted false interface IEnumerator with @@ -1378,7 +1377,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (SetResult<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (SetResult<'U> result) 1, result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) @@ -1544,7 +1543,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = if f value then this.Value <- true - pipeline.StopFurtherProcessing () + pipeline.StopFurtherProcessing 1 Unchecked.defaultof }) |> fun exists -> exists.Value @@ -1557,7 +1556,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = if element = value then this.Value <- true - pipeline.StopFurtherProcessing() + pipeline.StopFurtherProcessing 1 Unchecked.defaultof }) |> fun contains -> contains.Value @@ -1570,7 +1569,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = if not (f value) then this.Value <- false - pipeline.StopFurtherProcessing() + pipeline.StopFurtherProcessing 1 Unchecked.defaultof }) |> fun forall -> forall.Value @@ -1675,7 +1674,7 @@ namespace Microsoft.FSharp.Collections match f value with | (Some _) as some -> this.Value <- some - pipeline.StopFurtherProcessing() + pipeline.StopFurtherProcessing 1 | None -> () Unchecked.defaultof }) |> fun pick -> pick.Value @@ -1694,7 +1693,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = if f value then this.Value <- Some value - pipeline.StopFurtherProcessing() + pipeline.StopFurtherProcessing 1 Unchecked.defaultof }) |> fun find -> find.Value @@ -1785,7 +1784,7 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'T, SeqComposer.Values>).Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -1936,7 +1935,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = if p value then this.Value._1 <- Some(this.Value._2) - pipeline.StopFurtherProcessing() + pipeline.StopFurtherProcessing 1 else this.Value._2 <- this.Value._2 + 1 Unchecked.defaultof @@ -2209,7 +2208,7 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'a, SeqComposer.Values<'a, int>>).Value._2 = 0 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun total -> LanguagePrimitives.DivideByInt< ^a> total.Value._1 total.Value._2 @@ -2224,7 +2223,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- this.Value._2 + 1 Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'T,SeqComposer.Values<'U, int>>).Value._2 = 0 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun total -> LanguagePrimitives.DivideByInt< ^U> total.Value._1 total.Value._2 @@ -2243,7 +2242,7 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -2267,7 +2266,7 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -2303,7 +2302,7 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -2327,7 +2326,7 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index 7e94539f3ea..92b49d572ae 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -15,11 +15,11 @@ namespace Microsoft.FSharp.Collections module Seq = module SeqComposer = type ISeqComponent = - abstract OnComplete : unit -> unit + abstract OnComplete : int -> unit abstract OnDispose : unit -> unit type ISeqPipeline = - abstract StopFurtherProcessing : unit -> unit + abstract StopFurtherProcessing : int -> unit [] type SeqConsumer<'T,'U> = From 9c2104233581b7156e72669cb60657d8e6f8afc8 Mon Sep 17 00:00:00 2001 From: liboz Date: Sat, 22 Oct 2016 23:04:03 +0200 Subject: [PATCH 22/59] Seq.scan Seq.tryItem, tryHead, head, exactlyOne --- src/fsharp/FSharp.Core/seq.fs | 97 +++++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 34 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 7503c1f47a5..a9a2faa4ac6 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -592,6 +592,10 @@ namespace Microsoft.FSharp.Collections inherit SeqComponentFactory<'T,'T*'T> () override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T*'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Pairwise (next, haltingIdx) + and ScanFactory<'T,'State> (folder:'State->'T->'State, initialState:'State) = + inherit SeqComponentFactory<'T,'State> () + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'State,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next, haltingIdx) + and SkipFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Skip (count, next, haltingIdx) @@ -828,6 +832,16 @@ namespace Microsoft.FSharp.Collections lastValue <- input Helpers.avoidTailCall (next.ProcessNext currentPair) + and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:SeqConsumer<'State,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) + + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + let mutable foldResult = initialState + + override __.ProcessNext (input:'T) : bool = + foldResult <- f.Invoke(foldResult, input) + Helpers.avoidTailCall (next.ProcessNext foldResult) + and Skip<'T,'V> (skipCount:int, next:SeqConsumer<'T,'V>, haltingIdx:int) = inherit SeqComponent<'T,'V>(next, haltingIdx) @@ -1515,10 +1529,18 @@ namespace Microsoft.FSharp.Collections [] let tryItem i (source : seq<'T>) = - checkNonNull "source" source if i < 0 then None else - use e = source.GetEnumerator() - IEnumerator.tryItem i e + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, SeqComposer.Values>> (SeqComposer.Values<_, _> (0, None)) with + override this.ProcessNext value = + if this.Value._1 = i then + this.Value._2 <- Some value + pipeline.StopFurtherProcessing 1 + else + this.Value._1 <- this.Value._1 + 1 + Unchecked.defaultof }) + |> fun item -> item.Value._2 [] let nth i (source : seq<'T>) = item i source @@ -1899,15 +1921,10 @@ namespace Microsoft.FSharp.Collections source |> seqFactory (SeqComposer.PairwiseFactory ()) [] - let scan<'T,'State> f (z:'State) (source : seq<'T>) = - checkNonNull "source" source - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - seq { let zref = ref z - yield !zref - use ie = source.GetEnumerator() - while ie.MoveNext() do - zref := f.Invoke(!zref, ie.Current) - yield !zref } + let scan<'T,'State> f (z:'State) (source : seq<'T>): seq<'State> = + let first = [|z|] :> IEnumerable<'State> + let rest = source |> seqFactory (SeqComposer.ScanFactory (f, z)) + upcast SeqComposer.Enumerable.ConcatEnumerable [|first; rest;|] [] let tryFindBack f (source : seq<'T>) = @@ -2373,7 +2390,6 @@ namespace Microsoft.FSharp.Collections ok <- p.Invoke(e1.Current, e2.Current) ok - [] let exists2 p (source1: seq<_>) (source2: seq<_>) = checkNonNull "source1" source1 @@ -2385,20 +2401,23 @@ namespace Microsoft.FSharp.Collections while (not ok && e1.MoveNext() && e2.MoveNext()) do ok <- p.Invoke(e1.Current, e2.Current) ok + + [] + let tryHead (source : seq<_>) = + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, Option<'T>> (None) with + override this.ProcessNext value = + this.Value <- Some value + pipeline.StopFurtherProcessing 1 + Unchecked.defaultof }) + |> fun head -> head.Value [] let head (source : seq<_>) = - checkNonNull "source" source - use e = source.GetEnumerator() - if (e.MoveNext()) then e.Current - else invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - - [] - let tryHead (source : seq<_>) = - checkNonNull "source" source - use e = source.GetEnumerator() - if (e.MoveNext()) then Some e.Current - else None + match tryHead source with + | None -> invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + | Some x -> x [] let tail (source: seq<'T>) = @@ -2428,16 +2447,26 @@ namespace Microsoft.FSharp.Collections [] let exactlyOne (source : seq<_>) = - checkNonNull "source" source - use e = source.GetEnumerator() - if e.MoveNext() then - let v = e.Current - if e.MoveNext() then - invalidArg "source" (SR.GetString(SR.inputSequenceTooLong)) - else - v - else - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, SeqComposer.Values> (SeqComposer.Values(true, Unchecked.defaultof<'T>, false)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + else + this.Value._3 <- true + pipeline.StopFurtherProcessing 1 + Unchecked.defaultof + interface SeqComposer.ISeqComponent with + member this.OnComplete _ = + let value = (this:?>SeqComposer.Folder<'T,SeqComposer.Values>) + if value.Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + elif value.Value._3 then + invalidArg "source" (SR.GetString(SR.inputSequenceTooLong)) + }) + |> fun one -> one.Value._2 [] let rev source = From 99e17ea44ff53e28ec4964c49175a11bb9abda69 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Mon, 24 Oct 2016 11:17:12 +0200 Subject: [PATCH 23/59] Another take on halting index - Shrank public interface by removing ISeqPipeline from ForEach. - Renamed haltingIdx to pipelineDepth - Removed haltingIdx from where I could Remove mutable state in SeqComponentFactory - Changed "depth" to "idx" to better communicate the function Simplified use of OnComplete & OnDispose Pushed the chaining functionality into the interface and added extra methods on SeqConsumer. This means the consumer can ignore the interface and just implement their version, which means less likely to be an issue of the message not being chained correctly. It also has the advantage that in the object expressions we don't have to cast back to the base type, which was a potentital area for errors. Starting to finalise namespacing and comments Still playing around, happy for some input here... --- src/fsharp/FSharp.Core/seq.fs | 667 ++++++++++++++++----------------- src/fsharp/FSharp.Core/seq.fsi | 104 ++--- 2 files changed, 389 insertions(+), 382 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index a9a2faa4ac6..6617485d729 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -448,60 +448,79 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = - module SeqComposer = + module Composer = open IEnumerator - type ISeqComponent = - abstract OnComplete : int -> unit - abstract OnDispose : unit -> unit + module Internal = + type PipeIdx = int + type ``PipeIdx?`` = Nullable + let emptyPipeIdx = Nullable () + let inline getPipeIdx (maybePipeIdx:``PipeIdx?``) = if maybePipeIdx.HasValue then maybePipeIdx.Value else 1 + let inline makePipeIdx (pipeIdx:PipeIdx) = Nullable pipeIdx - type ISeqPipeline = - abstract StopFurtherProcessing : int -> unit + type ICompletionChaining = + abstract OnComplete : PipeIdx -> unit + abstract OnDispose : unit -> unit - [] - type SeqConsumer<'T,'U> () = - abstract ProcessNext : input:'T -> bool + type IPipeline = + abstract StopFurtherProcessing : PipeIdx -> unit - interface ISeqComponent with - member __.OnComplete _ = () - member __.OnDispose() = () + [] + type Consumer<'T,'U> () = + abstract ProcessNext : input:'T -> bool + + abstract OnComplete : PipeIdx -> unit + abstract OnDispose : unit -> unit + + default __.OnComplete _ = () + default __.OnDispose () = () + + interface ICompletionChaining with + member this.OnComplete terminatingIdx = + this.OnComplete terminatingIdx - [] - type Values<'a,'b> = - val mutable _1 : 'a - val mutable _2 : 'b + member this.OnDispose () = + try this.OnDispose () + finally () - new (a:'a, b: 'b) = { - _1 = a - _2 = b - } + [] + type Values<'a,'b> = + val mutable _1 : 'a + val mutable _2 : 'b - [] - type Values<'a,'b,'c> = - val mutable _1 : 'a - val mutable _2 : 'b - val mutable _3 : 'c + new (a:'a, b: 'b) = { + _1 = a + _2 = b + } - new (a:'a, b:'b, c:'c) = { - _1 = a - _2 = b - _3 = c - } + [] + type Values<'a,'b,'c> = + val mutable _1 : 'a + val mutable _2 : 'b + val mutable _3 : 'c - [] - type Folder<'T, 'U> = - inherit SeqConsumer<'T,'T> + new (a:'a, b:'b, c:'c) = { + _1 = a + _2 = b + _3 = c + } - val mutable Value : 'U + [] + type Folder<'T, 'U> = + inherit Consumer<'T,'T> + + val mutable Value : 'U - new (init) = { - inherit SeqConsumer<'T,'T>() - Value = init - } + new (init) = { + inherit Consumer<'T,'T>() + Value = init + } + + [] + type SeqEnumerable<'T>() = + abstract member ForEach<'a when 'a :> Consumer<'T,'T>> : f:((unit->unit)->'a) -> 'a - [] - type SeqEnumerable<'T>() = - abstract member ForEach<'a when 'a :> SeqConsumer<'T,'T>> : f:(ISeqPipeline->'a) -> 'a + open Internal module Helpers = // used for performance reasons; these are not recursive calls, so should be safe @@ -514,143 +533,145 @@ namespace Microsoft.FSharp.Collections let inline upcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) - let inline upcastISeqComponent (t:#ISeqComponent) : ISeqComponent = (# "" t : ISeqComponent #) + let inline upcastISeqComponent (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) - let seqComponentTail = - { new ISeqComponent with - member __.OnComplete _ = () - member __.OnDispose() = () } + type [] SeqComponentFactory<'T,'U> (pipeIdx:``PipeIdx?``) = + abstract Create<'V> : IPipeline -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> - type [] SeqComponentFactory<'T,'U> () = - abstract Create<'V> : ISeqPipeline -> SeqConsumer<'U,'V> -> haltingIdx:int -> SeqConsumer<'T,'V> + new() = SeqComponentFactory<'T,'U> (emptyPipeIdx) + + member __.PipeIdx = getPipeIdx pipeIdx + + and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>, secondPipeIdx:PipeIdx) = + inherit SeqComponentFactory<'T,'V> (makePipeIdx secondPipeIdx) - and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>) = - inherit SeqComponentFactory<'T,'V> () - override __.Create<'W> (result:ISeqPipeline) (next:SeqConsumer<'V,'W>) (haltingIdx:int) : SeqConsumer<'T,'W> = - first.Create result (second.Create result next (haltingIdx+1)) (haltingIdx+2) + override this.Create<'W> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'V,'W>) : Consumer<'T,'W> = + first.Create result pipeIdx (second.Create result (makePipeIdx secondPipeIdx) next) static member Combine (first:SeqComponentFactory<'T,'U>) (second:SeqComponentFactory<'U,'V>) : SeqComponentFactory<'T,'V> = - upcast ComposedFactory(first, second) + upcast ComposedFactory(first, second, first.PipeIdx+1) and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Choose (filter, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) and DistinctFactory<'T when 'T: equality> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Distinct (next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast DistinctBy (keyFunction, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Except (itemsToExclude, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) and FilterFactory<'T> (filter:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = match next with - | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter haltingIdx - | _ -> upcast Filter (filter, next, haltingIdx) + | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter + | _ -> upcast Filter (filter, next) and IdentityFactory<'T> () = inherit SeqComponentFactory<'T,'T> () static let singleton = IdentityFactory<'T>() - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (_haltingIdx:int) : SeqConsumer<'T,'V> = next + override __.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next static member IdentityFactory = singleton and MapFactory<'T,'U> (map:'T->'U) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = match next with - | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map haltingIdx - | _ -> upcast Map<_,_,_> (map, next, haltingIdx) + | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map + | _ -> upcast Map<_,_,_> (map, next) and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'First,'V> = upcast Map2First (map, input2, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, result, next, getPipeIdx pipeIdx) and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = inherit SeqComponentFactory<'Second,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'Second,'V> = upcast Map2Second (map, input1, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, result, next, getPipeIdx pipeIdx) and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'First,'V> = upcast Map3 (map, input2, input3, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, result, next, getPipeIdx pipeIdx) and MapiFactory<'T,'U> (mapi:int->'T->'U) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Mapi (mapi, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Mapi (mapi, next) and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'First,'V> = upcast Mapi2 (map, input2, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, result, next, getPipeIdx pipeIdx) and PairwiseFactory<'T> () = inherit SeqComponentFactory<'T,'T*'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T*'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Pairwise (next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) and ScanFactory<'T,'State> (folder:'State->'T->'State, initialState:'State) = inherit SeqComponentFactory<'T,'State> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'State,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) and SkipFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Skip (count, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, next) and SkipWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast SkipWhile (predicate, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) and TakeWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast TakeWhile (predicate, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, result, next, getPipeIdx pipeIdx) and TakeFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Take (count, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, result, next, getPipeIdx pipeIdx) and TailFactory<'T> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Tail<'T,'V> (next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) and TruncateFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Truncate (count, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, result, next, getPipeIdx pipeIdx) - and [] SeqComponent<'T,'U> (next:ISeqComponent, haltingIdx:int) = - inherit SeqConsumer<'T,'U>() + and [] SeqComponent<'T,'U> (next:ICompletionChaining) = + inherit Consumer<'T,'U>() - // Seq.init(Infinite)? lazily uses Current. The only SeqComposer component that can do that is Skip + // Seq.init(Infinite)? lazily uses Current. The only Composer component that can do that is Skip // and it can only do it at the start of a sequence abstract Skipping : unit -> bool - abstract CreateMap<'S> : map:('S->'T) -> haltingIdx:int -> SeqComponent<'S,'U> - abstract CreateFilter : filter:('T->bool) -> haltingIdx:int -> SeqComponent<'T,'U> + abstract CreateMap<'S> : map:('S->'T) -> SeqComponent<'S,'U> + abstract CreateFilter : filter:('T->bool) -> SeqComponent<'T,'U> - interface ISeqComponent with - member __.OnComplete halted = next.OnComplete halted - member __.OnDispose () = next.OnDispose () - - member __.HaltingIdx = haltingIdx + interface ICompletionChaining with + member this.OnComplete terminatingIdx = + this.OnComplete terminatingIdx + next.OnComplete terminatingIdx + member this.OnDispose () = + try this.OnDispose () + finally next.OnDispose () default __.Skipping () = false - default this.CreateMap<'S> (map:'S->'T) (haltingIdx:int) = upcast Map<_,_,_> (map, this, haltingIdx) - default this.CreateFilter (filter:'T->bool) (haltingIdx:int) = upcast Filter (filter, this, haltingIdx) + default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) + default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) - and Choose<'T,'U,'V> (choose:'T->option<'U>, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Choose<'T,'U,'V> (choose:'T->option<'U>, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = match choose input with | Some value -> Helpers.avoidTailCall (next.ProcessNext value) | None -> false - and Distinct<'T,'V when 'T: equality> (next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Distinct<'T,'V when 'T: equality> (next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) @@ -660,8 +681,8 @@ namespace Microsoft.FSharp.Collections else false - and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) @@ -671,8 +692,8 @@ namespace Microsoft.FSharp.Collections else false - and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) @@ -682,10 +703,10 @@ namespace Microsoft.FSharp.Collections else false - and Filter<'T,'V> (filter:'T->bool, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Filter<'T,'V> (filter:'T->bool, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) - override this.CreateMap<'S> (map:'S->'T) (haltingIdx:int) = upcast MapThenFilter<_,_,_> (map, filter, next, haltingIdx) + override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) override __.ProcessNext (input:'T) : bool = if filter input then @@ -693,8 +714,8 @@ namespace Microsoft.FSharp.Collections else false - and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = if filter input then @@ -702,16 +723,16 @@ namespace Microsoft.FSharp.Collections else false - and Map<'T,'U,'V> (map:'T->'U, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Map<'T,'U,'V> (map:'T->'U, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) - override this.CreateFilter (filter:'T->bool) (haltingIdx:int) = upcast FilterThenMap (filter, map, next, haltingIdx) + override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) override __.ProcessNext (input:'T) : bool = Helpers.avoidTailCall (next.ProcessNext (map input)) - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'First,'V>(next, haltingIdx) + and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map @@ -720,18 +741,14 @@ namespace Microsoft.FSharp.Collections if input2.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) else - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx false - interface ISeqComponent with - override __.OnDispose () = - try - input2.Dispose () - finally - (Helpers.upcastISeqComponent next).OnDispose () + override __.OnDispose () = + input2.Dispose () - and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'Second,'V>(next, haltingIdx) + and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + inherit SeqComponent<'Second,'V>(next) let input1 = enumerable1.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map @@ -740,18 +757,14 @@ namespace Microsoft.FSharp.Collections if input1.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) else - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx false - interface ISeqComponent with - override __.OnDispose () = - try - input1.Dispose () - finally - (Helpers.upcastISeqComponent next).OnDispose () + override __.OnDispose () = + input1.Dispose () - and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'First,'V>(next, haltingIdx) + and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () let input3 = enumerable3.GetEnumerator () @@ -761,21 +774,15 @@ namespace Microsoft.FSharp.Collections if input2.MoveNext () && input3.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) else - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx false - interface ISeqComponent with - override __.OnDispose () = - try - input2.Dispose () - finally - try - input3.Dispose () - finally - (Helpers.upcastISeqComponent next).OnDispose () + override __.OnDispose () = + try input2.Dispose () + finally input3.Dispose () - and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = let u = map input @@ -784,8 +791,8 @@ namespace Microsoft.FSharp.Collections else false - and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) let mutable idx = 0 let mapi' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt mapi @@ -794,8 +801,8 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) - and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'First,'V>(next, haltingIdx) + and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + inherit SeqComponent<'First,'V>(next) let mutable idx = 0 let input2 = enumerable2.GetEnumerator () @@ -806,18 +813,14 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) else - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx false - interface ISeqComponent with - override __.OnDispose () = - try - input2.Dispose () - finally - (Helpers.upcastISeqComponent next).OnDispose () + override __.OnDispose () = + input2.Dispose () - and Pairwise<'T,'V> (next:SeqConsumer<'T*'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Pairwise<'T,'V> (next:Consumer<'T*'T,'V>) = + inherit SeqComponent<'T,'V>(next) let mutable isFirst = true let mutable lastValue = Unchecked.defaultof<'T> @@ -832,8 +835,8 @@ namespace Microsoft.FSharp.Collections lastValue <- input Helpers.avoidTailCall (next.ProcessNext currentPair) - and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:SeqConsumer<'State,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:Consumer<'State,'V>) = + inherit SeqComponent<'T,'V>(next) let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let mutable foldResult = initialState @@ -842,8 +845,8 @@ namespace Microsoft.FSharp.Collections foldResult <- f.Invoke(foldResult, input) Helpers.avoidTailCall (next.ProcessNext foldResult) - and Skip<'T,'V> (skipCount:int, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Skip<'T,'V> (skipCount:int, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let mutable count = 0 @@ -861,16 +864,14 @@ namespace Microsoft.FSharp.Collections else Helpers.avoidTailCall (next.ProcessNext input) - interface ISeqComponent with - override __.OnComplete halted = - if count < skipCount then - let x = skipCount - count - invalidOpFmt "tried to skip {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - (Helpers.upcastISeqComponent next).OnComplete halted + override __.OnComplete _ = + if count < skipCount then + let x = skipCount - count + invalidOpFmt "tried to skip {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - and SkipWhile<'T,'V> (predicate:'T->bool, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and SkipWhile<'T,'V> (predicate:'T->bool, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let mutable skip = true @@ -884,29 +885,27 @@ namespace Microsoft.FSharp.Collections else Helpers.avoidTailCall (next.ProcessNext input) - and Take<'T,'V> (takeCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit Truncate<'T, 'V>(takeCount, result, next, haltingIdx) + and Take<'T,'V> (takeCount:int, result:IPipeline, next:Consumer<'T,'V>, pipelineIdx:int) = + inherit Truncate<'T, 'V>(takeCount, result, next, pipelineIdx) - interface ISeqComponent with - override this.OnComplete halted = - if halted = 0 || halted > haltingIdx && this.Count < takeCount then - let x = takeCount - this.Count - invalidOpFmt "tried to take {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - (Helpers.upcastISeqComponent next).OnComplete halted + override this.OnComplete terminatingIdx = + if terminatingIdx < pipelineIdx && this.Count < takeCount then + let x = takeCount - this.Count + invalidOpFmt "tried to take {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - and TakeWhile<'T,'V> (predicate:'T->bool, result:ISeqPipeline, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and TakeWhile<'T,'V> (predicate:'T->bool, result:IPipeline, next:Consumer<'T,'V>, pipeIdx:int) = + inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = if predicate input then Helpers.avoidTailCall (next.ProcessNext input) else - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx false - and Tail<'T, 'V> (next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Tail<'T, 'V> (next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let mutable first = true @@ -917,14 +916,12 @@ namespace Microsoft.FSharp.Collections else Helpers.avoidTailCall (next.ProcessNext input) - interface ISeqComponent with - override this.OnComplete halted = - if first then - invalidArg "source" (SR.GetString(SR.notEnoughElements)) - (Helpers.upcastISeqComponent next).OnComplete halted + override this.OnComplete _ = + if first then + invalidArg "source" (SR.GetString(SR.notEnoughElements)) - and Truncate<'T,'V> (truncateCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Truncate<'T,'V> (truncateCount:int, result:IPipeline, next:Consumer<'T,'V>, pipeIdx:int) = + inherit SeqComponent<'T,'V>(next) let mutable count = 0 @@ -934,10 +931,10 @@ namespace Microsoft.FSharp.Collections if count < truncateCount then count <- count + 1 if count = truncateCount then - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx next.ProcessNext input else - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx false type SeqProcessNextStates = @@ -950,48 +947,48 @@ namespace Microsoft.FSharp.Collections member val Current = Unchecked.defaultof<'T> with get, set member val SeqState = SeqProcessNextStates.NotStarted with get, set - member __.Halted = haltedIdx + member __.HaltedIdx = haltedIdx - interface ISeqPipeline with - member __.StopFurtherProcessing haltingIdx = haltedIdx <- haltingIdx + interface IPipeline with + member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx // SetResult<> is used at the end of the chain of SeqComponents to assign the final value type SetResult<'T> (result:Result<'T>) = - inherit SeqConsumer<'T,'T>() + inherit Consumer<'T,'T>() override __.ProcessNext (input:'T) : bool = result.Current <- input true type Pipeline() = - let mutable halted = 0 - interface ISeqPipeline with member x.StopFurtherProcessing haltingIdx = halted <- haltingIdx - member __.Halted = halted + let mutable haltedIdx = 0 + interface IPipeline with member x.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx + member __.HaltedIdx = haltedIdx module ForEach = - let enumerable (enumerable:IEnumerable<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let enumerable (enumerable:IEnumerable<'T>) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = use enumerator = enumerable.GetEnumerator () - while (pipeline.Halted = 0) && (enumerator.MoveNext ()) do + while (pipeline.HaltedIdx = 0) && (enumerator.MoveNext ()) do consumer.ProcessNext enumerator.Current |> ignore - let array (array:array<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let array (array:array<'T>) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = let mutable idx = 0 - while (pipeline.Halted = 0) && (idx < array.Length) do + while (pipeline.HaltedIdx = 0) && (idx < array.Length) do consumer.ProcessNext array.[idx] |> ignore idx <- idx + 1 - let list (alist:list<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let list (alist:list<'T>) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = let rec iterate lst = - match pipeline.Halted, lst with + match pipeline.HaltedIdx, lst with | 0, hd :: tl -> consumer.ProcessNext hd |> ignore iterate tl | _ -> () iterate alist - let unfold (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let unfold (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = let rec iterate current = - match pipeline.Halted, generator current with + match pipeline.HaltedIdx, generator current with | 0, Some (item, next) -> consumer.ProcessNext item |> ignore iterate next @@ -999,16 +996,16 @@ namespace Microsoft.FSharp.Collections iterate state - let makeIsSkipping (consumer:SeqConsumer<'T,'U>) = + let makeIsSkipping (consumer:Consumer<'T,'U>) = match consumer with | :? SeqComponent<'T,'U> as c -> c.Skipping | _ -> fun () -> false - let init f (terminatingIdx:int) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let init f (terminatingIdx:int) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = let mutable idx = -1 let isSkipping = makeIsSkipping consumer let mutable maybeSkipping = true - while (pipeline.Halted = 0) && (idx < terminatingIdx) do + while (pipeline.HaltedIdx = 0) && (idx < terminatingIdx) do if maybeSkipping then maybeSkipping <- isSkipping () @@ -1017,13 +1014,13 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 - let execute (f:ISeqPipeline->#SeqConsumer<'U,'U>) (current:SeqComponentFactory<'T,'U>) executeOn = + let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:SeqComponentFactory<'T,'U>) executeOn = let pipeline = Pipeline() - let result = f pipeline - let consumer = current.Create pipeline result 1 + let result = f (fun () -> (pipeline:>IPipeline).StopFurtherProcessing (current.PipeIdx+1)) + let consumer = current.Create pipeline emptyPipeIdx result try executeOn pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete pipeline.Halted + (Helpers.upcastISeqComponent consumer).OnComplete pipeline.HaltedIdx result finally (Helpers.upcastISeqComponent consumer).OnDispose () @@ -1045,7 +1042,7 @@ namespace Microsoft.FSharp.Collections static member Element = element [] - type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ISeqComponent) = + type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ICompletionChaining) = interface IDisposable with member __.Dispose() : unit = seqComponent.OnDispose () @@ -1082,18 +1079,18 @@ namespace Microsoft.FSharp.Collections member this.GetEnumerator () : IEnumerator<'T> = failwith "library implementation error: derived class should implement (should be abstract)" - and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = + and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = inherit EnumeratorBase<'U>(result, seqComponent) let rec moveNext () = - if (result.Halted = 0) && source.MoveNext () then + if (result.HaltedIdx = 0) && source.MoveNext () then if seqComponent.ProcessNext source.Current then true else moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete result.Halted + (Helpers.upcastISeqComponent seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1114,12 +1111,12 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (SetResult<'U> result) 1, result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.enumerable enumerable) and ConcatEnumerator<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = @@ -1171,7 +1168,7 @@ namespace Microsoft.FSharp.Collections override this.Append source = Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = + override this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable this) and ConcatEnumerable<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = @@ -1184,14 +1181,14 @@ namespace Microsoft.FSharp.Collections override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = Helpers.upcastEnumerable (Enumerable<'T,'V>(this, next)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = + override this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable this) let create enumerable current = Helpers.upcastEnumerable (Enumerable(enumerable, current)) module Array = - type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = + type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let mutable idx = 0 @@ -1206,7 +1203,7 @@ namespace Microsoft.FSharp.Collections initMoveNext <- ignore let rec moveNext () = - if (result.Halted = 0) && idx < array.Length then + if (result.HaltedIdx = 0) && idx < array.Length then idx <- idx+1 if seqComponent.ProcessNext array.[idx-1] then true @@ -1214,7 +1211,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete result.Halted + (Helpers.upcastISeqComponent seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1228,12 +1225,12 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result (SetResult<'U> result) 1, result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.array (delayedArray ())) let createDelayed (delayedArray:unit->array<'T>) (current:SeqComponentFactory<'T,'U>) = @@ -1249,13 +1246,13 @@ namespace Microsoft.FSharp.Collections create array IdentityFactory.IdentityFactory module List = - type Enumerator<'T,'U>(alist:list<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = + type Enumerator<'T,'U>(alist:list<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let mutable list = alist let rec moveNext current = - match result.Halted, current with + match result.HaltedIdx, current with | 0, head::tail -> if seqComponent.ProcessNext head then list <- tail @@ -1264,7 +1261,7 @@ namespace Microsoft.FSharp.Collections moveNext tail | _ -> result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete result.Halted + (Helpers.upcastISeqComponent seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1278,25 +1275,25 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (SetResult<'U> result) 1, result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.list alist) let create alist current = Helpers.upcastEnumerable (Enumerable(alist, current)) module Unfold = - type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:SeqConsumer<'T,'U>, signal:Result<'U>) = + type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, signal:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) let mutable current = state let rec moveNext () = - match signal.Halted, generator current with + match signal.HaltedIdx, generator current with | 0, Some (item, nextState) -> current <- nextState if seqComponent.ProcessNext item then @@ -1316,12 +1313,12 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (SetResult<'U> result) 1, result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.unfold generator state) module Init = @@ -1346,7 +1343,7 @@ namespace Microsoft.FSharp.Collections else System.Int32.MaxValue - type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:SeqConsumer<'T,'U>, signal:Result<'U>) = + type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:Consumer<'T,'U>, signal:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) let isSkipping = @@ -1359,7 +1356,7 @@ namespace Microsoft.FSharp.Collections let mutable idx = -1 let rec moveNext () = - if (signal.Halted = 0) && idx < terminatingIdx then + if (signal.HaltedIdx = 0) && idx < terminatingIdx then idx <- idx + 1 if maybeSkipping then @@ -1373,11 +1370,11 @@ namespace Microsoft.FSharp.Collections true else moveNext () - elif (signal.Halted = 0) && idx = System.Int32.MaxValue then + elif (signal.HaltedIdx = 0) && idx = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) else signal.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete signal.Halted + (Helpers.upcastISeqComponent seqComponent).OnComplete signal.HaltedIdx false interface IEnumerator with @@ -1391,12 +1388,12 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (SetResult<'U> result) 1, result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) - override this.ForEach (createResult:ISeqPipeline->#SeqConsumer<'U,'U>) = + override this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = let terminatingIdx = getTerminatingIdx count ForEach.execute createResult current (ForEach.init f terminatingIdx) @@ -1463,7 +1460,7 @@ namespace Microsoft.FSharp.Collections override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = + override this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable (Helpers.upcastEnumerable this)) #if FX_NO_ICLONEABLE @@ -1477,13 +1474,13 @@ namespace Microsoft.FSharp.Collections let inline indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) [] - let toComposer (source:seq<'T>): SeqComposer.SeqEnumerable<'T> = + let toComposer (source:seq<'T>): Composer.Internal.SeqEnumerable<'T> = checkNonNull "source" source match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> upcast s - | :? array<'T> as a -> upcast SeqComposer.Array.Enumerable((fun () -> a), SeqComposer.IdentityFactory.IdentityFactory) - | :? list<'T> as a -> upcast SeqComposer.List.Enumerable(a, SeqComposer.IdentityFactory.IdentityFactory) - | _ -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(source, SeqComposer.IdentityFactory.IdentityFactory) + | :? Composer.Enumerable.EnumerableBase<'T> as s -> upcast s + | :? array<'T> as a -> upcast Composer.Array.Enumerable((fun () -> a), Composer.IdentityFactory.IdentityFactory) + | :? list<'T> as a -> upcast Composer.List.Enumerable(a, Composer.IdentityFactory.IdentityFactory) + | _ -> upcast Composer.Enumerable.Enumerable<'T,'T>(source, Composer.IdentityFactory.IdentityFactory) let inline foreach f (source:seq<_>) = source @@ -1495,26 +1492,26 @@ namespace Microsoft.FSharp.Collections [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> = - SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Unfold.Enumerable<'T,'T,'State>(generator, state, SeqComposer.IdentityFactory.IdentityFactory)) + Composer.Helpers.upcastEnumerable (new Composer.Unfold.Enumerable<'T,'T,'State>(generator, state, Composer.IdentityFactory.IdentityFactory)) [] let empty<'T> = (EmptyEnumerable :> seq<'T>) [] let initInfinite<'T> (f:int->'T) : IEnumerable<'T> = - SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Init.EnumerableDecider<'T>(Nullable (), f)) + Composer.Helpers.upcastEnumerable (new Composer.Init.EnumerableDecider<'T>(Nullable (), f)) [] let init<'T> (count:int) (f:int->'T) : IEnumerable<'T> = if count < 0 then invalidArgInputMustBeNonNegative "count" count elif count = 0 then empty else - SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Init.EnumerableDecider<'T>(Nullable count, f)) + Composer.Helpers.upcastEnumerable (new Composer.Init.EnumerableDecider<'T>(Nullable count, f)) [] let iter f (source : seq<'T>) = source |> foreach (fun _ -> - { new SeqComposer.SeqConsumer<'T,'T> () with + { new Composer.Internal.Consumer<'T,'T> () with override this.ProcessNext value = f value Unchecked.defaultof }) @@ -1531,12 +1528,12 @@ namespace Microsoft.FSharp.Collections let tryItem i (source : seq<'T>) = if i < 0 then None else source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, SeqComposer.Values>> (SeqComposer.Values<_, _> (0, None)) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Composer.Internal.Values>> (Composer.Internal.Values<_, _> (0, None)) with override this.ProcessNext value = if this.Value._1 = i then this.Value._2 <- Some value - pipeline.StopFurtherProcessing 1 + halt () else this.Value._1 <- this.Value._1 + 1 Unchecked.defaultof }) @@ -1550,7 +1547,7 @@ namespace Microsoft.FSharp.Collections let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) source |> foreach (fun _ -> - { new SeqComposer.Folder<'T, int> (0) with + { new Composer.Internal.Folder<'T, int> (0) with override this.ProcessNext value = f.Invoke(this.Value, value) this.Value <- this.Value + 1 @@ -1560,12 +1557,12 @@ namespace Microsoft.FSharp.Collections [] let exists f (source : seq<'T>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, bool> (false) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, bool> (false) with override this.ProcessNext value = if f value then this.Value <- true - pipeline.StopFurtherProcessing 1 + halt () Unchecked.defaultof }) |> fun exists -> exists.Value @@ -1573,12 +1570,12 @@ namespace Microsoft.FSharp.Collections [] let inline contains element (source : seq<'T>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, bool> (false) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, bool> (false) with override this.ProcessNext value = if element = value then this.Value <- true - pipeline.StopFurtherProcessing 1 + halt () Unchecked.defaultof }) |> fun contains -> contains.Value @@ -1586,12 +1583,12 @@ namespace Microsoft.FSharp.Collections [] let forall f (source : seq<'T>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, bool> (true) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, bool> (true) with override this.ProcessNext value = if not (f value) then this.Value <- false - pipeline.StopFurtherProcessing 1 + halt () Unchecked.defaultof }) |> fun forall -> forall.Value @@ -1628,51 +1625,51 @@ namespace Microsoft.FSharp.Collections let private seqFactory createSeqComponent (source:seq<'T>) = checkNonNull "source" source match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Compose createSeqComponent - | :? array<'T> as a -> SeqComposer.Array.create a createSeqComponent - | :? list<'T> as a -> SeqComposer.List.create a createSeqComponent - | _ -> SeqComposer.Enumerable.create source createSeqComponent + | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Compose createSeqComponent + | :? array<'T> as a -> Composer.Array.create a createSeqComponent + | :? list<'T> as a -> Composer.List.create a createSeqComponent + | _ -> Composer.Enumerable.create source createSeqComponent [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = - source |> seqFactory (SeqComposer.FilterFactory f) + source |> seqFactory (Composer.FilterFactory f) [] let where f source = filter f source [] let map<'T,'U> (f:'T->'U) (source:seq<'T>) : seq<'U> = - source |> seqFactory (SeqComposer.MapFactory f) + source |> seqFactory (Composer.MapFactory f) [] let mapi f source = - source |> seqFactory (SeqComposer.MapiFactory f) + source |> seqFactory (Composer.MapiFactory f) [] let mapi2 f source1 source2 = checkNonNull "source2" source2 - source1 |> seqFactory (SeqComposer.Mapi2Factory (f, source2)) + source1 |> seqFactory (Composer.Mapi2Factory (f, source2)) [] let map2<'T,'U,'V> (f:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = checkNonNull "source1" source1 match source1 with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Compose (SeqComposer.Map2FirstFactory (f, source2)) - | _ -> source2 |> seqFactory (SeqComposer.Map2SecondFactory (f, source1)) + | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Compose (Composer.Map2FirstFactory (f, source2)) + | _ -> source2 |> seqFactory (Composer.Map2SecondFactory (f, source1)) [] let map3 f source1 source2 source3 = checkNonNull "source2" source2 checkNonNull "source3" source3 - source1 |> seqFactory (SeqComposer.Map3Factory (f, source2, source3)) + source1 |> seqFactory (Composer.Map3Factory (f, source2, source3)) [] let choose f source = - source |> seqFactory (SeqComposer.ChooseFactory f) + source |> seqFactory (Composer.ChooseFactory f) [] let indexed source = - source |> seqFactory (SeqComposer.MapiFactory (fun i x -> i,x) ) + source |> seqFactory (Composer.MapiFactory (fun i x -> i,x) ) [] let zip source1 source2 = @@ -1690,13 +1687,13 @@ namespace Microsoft.FSharp.Collections [] let tryPick f (source : seq<'T>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, Option<'U>> (None) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Option<'U>> (None) with override this.ProcessNext value = match f value with | (Some _) as some -> this.Value <- some - pipeline.StopFurtherProcessing 1 + halt () | None -> () Unchecked.defaultof }) |> fun pick -> pick.Value @@ -1710,12 +1707,12 @@ namespace Microsoft.FSharp.Collections [] let tryFind f (source : seq<'T>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, Option<'T>> (None) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Option<'T>> (None) with override this.ProcessNext value = if f value then this.Value <- Some value - pipeline.StopFurtherProcessing 1 + halt () Unchecked.defaultof }) |> fun find -> find.Value @@ -1730,7 +1727,7 @@ namespace Microsoft.FSharp.Collections if count < 0 then invalidArgInputMustBeNonNegative "count" count (* Note: don't create or dispose any IEnumerable if n = 0 *) if count = 0 then empty else - source |> seqFactory (SeqComposer.TakeFactory count) + source |> seqFactory (Composer.TakeFactory count) [] let isEmpty (source : seq<'T>) = @@ -1746,7 +1743,7 @@ namespace Microsoft.FSharp.Collections [] let concat (sources:seq<#seq<'T>>) : seq<'T> = checkNonNull "sources" sources - upcast SeqComposer.Enumerable.ConcatEnumerable sources + upcast Composer.Enumerable.ConcatEnumerable sources [] let length (source : seq<'T>) = @@ -1768,7 +1765,7 @@ namespace Microsoft.FSharp.Collections source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,'State> (x) with + { new Composer.Internal.Folder<'T,'State> (x) with override this.ProcessNext value = this.Value <- f.Invoke (this.Value, value) Unchecked.defaultof }) @@ -1796,7 +1793,7 @@ namespace Microsoft.FSharp.Collections source |> foreach (fun _ -> - { new SeqComposer.Folder<'T, SeqComposer.Values> (SeqComposer.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -1805,9 +1802,8 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- f.Invoke (this.Value._2, value) Unchecked.defaultof - interface SeqComposer.ISeqComponent with member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'T, SeqComposer.Values>).Value._1 then + if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun reduced -> reduced.Value._2 @@ -1821,8 +1817,8 @@ namespace Microsoft.FSharp.Collections checkNonNull "source1" source1 checkNonNull "source2" source2 match source1 with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Append source2 - | _ -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Enumerable.AppendEnumerable<_>([source2; source1])) + | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Append source2 + | _ -> Composer.Helpers.upcastEnumerable (new Composer.Enumerable.AppendEnumerable<_>([source2; source1])) [] @@ -1860,7 +1856,7 @@ namespace Microsoft.FSharp.Collections [] let ofArray (source : 'T array) = checkNonNull "source" source - SeqComposer.Array.createId source + Composer.Array.createId source [] let toArray (source : seq<'T>) = @@ -1914,17 +1910,17 @@ namespace Microsoft.FSharp.Collections [] let truncate n (source: seq<'T>) = if n <= 0 then empty else - source |> seqFactory (SeqComposer.TruncateFactory n) + source |> seqFactory (Composer.TruncateFactory n) [] let pairwise<'T> (source:seq<'T>) : seq<'T*'T> = - source |> seqFactory (SeqComposer.PairwiseFactory ()) + source |> seqFactory (Composer.PairwiseFactory ()) [] let scan<'T,'State> f (z:'State) (source : seq<'T>): seq<'State> = let first = [|z|] :> IEnumerable<'State> - let rest = source |> seqFactory (SeqComposer.ScanFactory (f, z)) - upcast SeqComposer.Enumerable.ConcatEnumerable [|first; rest;|] + let rest = source |> seqFactory (Composer.ScanFactory (f, z)) + upcast Composer.Enumerable.ConcatEnumerable [|first; rest;|] [] let tryFindBack f (source : seq<'T>) = @@ -1947,12 +1943,12 @@ namespace Microsoft.FSharp.Collections [] let tryFindIndex p (source:seq<_>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, SeqComposer.Values, int>> (SeqComposer.Values<_,_>(None, 0)) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Composer.Internal.Values, int>> (Composer.Internal.Values<_,_>(None, 0)) with override this.ProcessNext value = if p value then this.Value._1 <- Some(this.Value._2) - pipeline.StopFurtherProcessing 1 + halt () else this.Value._2 <- this.Value._2 + 1 Unchecked.defaultof @@ -2116,11 +2112,11 @@ namespace Microsoft.FSharp.Collections [] let distinct source = - source |> seqFactory (SeqComposer.DistinctFactory ()) + source |> seqFactory (Composer.DistinctFactory ()) [] let distinctBy keyf source = - source |> seqFactory (SeqComposer.DistinctByFactory keyf) + source |> seqFactory (Composer.DistinctByFactory keyf) [] let sortBy keyf source = @@ -2129,7 +2125,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceBy keyf array array - SeqComposer.Array.createDelayedId delayedSort + Composer.Array.createDelayedId delayedSort [] let sort source = @@ -2138,7 +2134,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlace array array - SeqComposer.Array.createDelayedId delayedSort + Composer.Array.createDelayedId delayedSort [] let sortWith f source = @@ -2147,7 +2143,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceWith f array array - SeqComposer.Array.createDelayedId delayedSort + Composer.Array.createDelayedId delayedSort [] let inline sortByDescending keyf source = @@ -2198,7 +2194,7 @@ namespace Microsoft.FSharp.Collections let inline sum (source:seq<'a>) : 'a = source |> foreach (fun _ -> - { new SeqComposer.Folder<'a,'a> (LanguagePrimitives.GenericZero) with + { new Composer.Internal.Folder<'a,'a> (LanguagePrimitives.GenericZero) with override this.ProcessNext value = this.Value <- Checked.(+) this.Value value Unchecked.defaultof }) @@ -2208,7 +2204,7 @@ namespace Microsoft.FSharp.Collections let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + { new Composer.Internal.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with override this.ProcessNext value = this.Value <- Checked.(+) this.Value (f value) Unchecked.defaultof }) @@ -2218,15 +2214,14 @@ namespace Microsoft.FSharp.Collections let inline average (source: seq< ^a>) : ^a = source |> foreach (fun _ -> - { new SeqComposer.Folder<'a, SeqComposer.Values<'a, int>> (SeqComposer.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + { new Composer.Internal.Folder<'a, Composer.Internal.Values<'a, int>> (Composer.Internal.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 value this.Value._2 <- this.Value._2 + 1 Unchecked.defaultof - interface SeqComposer.ISeqComponent with member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'a, SeqComposer.Values<'a, int>>).Value._2 = 0 then + if this.Value._2 = 0 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun total -> LanguagePrimitives.DivideByInt< ^a> total.Value._1 total.Value._2 @@ -2234,14 +2229,14 @@ namespace Microsoft.FSharp.Collections let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,SeqComposer.Values<'U, int>> (SeqComposer.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + { new Composer.Internal.Folder<'T,Composer.Internal.Values<'U, int>> (Composer.Internal.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 (f value) this.Value._2 <- this.Value._2 + 1 Unchecked.defaultof - interface SeqComposer.ISeqComponent with + member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'T,SeqComposer.Values<'U, int>>).Value._2 = 0 then + if this.Value._2 = 0 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun total -> LanguagePrimitives.DivideByInt< ^U> total.Value._1 total.Value._2 @@ -2249,7 +2244,7 @@ namespace Microsoft.FSharp.Collections let inline min (source: seq<_>) = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2258,9 +2253,8 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- value Unchecked.defaultof - interface SeqComposer.ISeqComponent with member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun min -> min.Value._2 @@ -2269,7 +2263,7 @@ namespace Microsoft.FSharp.Collections let inline minBy (f : 'T -> 'U) (source: seq<'T>) : 'T = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with override this.ProcessNext value = match this.Value._1, f value with | true, valueU -> @@ -2282,9 +2276,8 @@ namespace Microsoft.FSharp.Collections | _ -> () Unchecked.defaultof - interface SeqComposer.ISeqComponent with member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun min -> min.Value._3 @@ -2309,7 +2302,7 @@ namespace Microsoft.FSharp.Collections let inline max (source: seq<_>) = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2318,9 +2311,8 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- value Unchecked.defaultof - interface SeqComposer.ISeqComponent with member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun max -> max.Value._2 @@ -2329,7 +2321,7 @@ namespace Microsoft.FSharp.Collections let inline maxBy (f : 'T -> 'U) (source: seq<'T>) : 'T = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with override this.ProcessNext value = match this.Value._1, f value with | true, valueU -> @@ -2342,9 +2334,8 @@ namespace Microsoft.FSharp.Collections | _ -> () Unchecked.defaultof - interface SeqComposer.ISeqComponent with member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun min -> min.Value._3 @@ -2368,15 +2359,15 @@ namespace Microsoft.FSharp.Collections *) [] let takeWhile p (source: seq<_>) = - source |> seqFactory (SeqComposer.TakeWhileFactory p) + source |> seqFactory (Composer.TakeWhileFactory p) [] let skip count (source: seq<_>) = - source |> seqFactory (SeqComposer.SkipFactory count) + source |> seqFactory (Composer.SkipFactory count) [] let skipWhile p (source: seq<_>) = - source |> seqFactory (SeqComposer.SkipWhileFactory p) + source |> seqFactory (Composer.SkipWhileFactory p) [] let forall2 p (source1: seq<_>) (source2: seq<_>) = @@ -2405,11 +2396,11 @@ namespace Microsoft.FSharp.Collections [] let tryHead (source : seq<_>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, Option<'T>> (None) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Option<'T>> (None) with override this.ProcessNext value = this.Value <- Some value - pipeline.StopFurtherProcessing 1 + halt () Unchecked.defaultof }) |> fun head -> head.Value @@ -2421,13 +2412,13 @@ namespace Microsoft.FSharp.Collections [] let tail (source: seq<'T>) = - source |> seqFactory (SeqComposer.TailFactory ()) + source |> seqFactory (Composer.TailFactory ()) [] let tryLast (source : seq<_>) = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T, SeqComposer.Values> (SeqComposer.Values(true, Unchecked.defaultof<'T>)) with + { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2448,24 +2439,22 @@ namespace Microsoft.FSharp.Collections [] let exactlyOne (source : seq<_>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, SeqComposer.Values> (SeqComposer.Values(true, Unchecked.defaultof<'T>, false)) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values(true, Unchecked.defaultof<'T>, false)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false this.Value._2 <- value else this.Value._3 <- true - pipeline.StopFurtherProcessing 1 + halt () Unchecked.defaultof - interface SeqComposer.ISeqComponent with + member this.OnComplete _ = - let value = (this:?>SeqComposer.Folder<'T,SeqComposer.Values>) - if value.Value._1 then + if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - elif value.Value._3 then - invalidArg "source" (SR.GetString(SR.inputSequenceTooLong)) - }) + elif this.Value._3 then + invalidArg "source" (SR.GetString(SR.inputSequenceTooLong)) }) |> fun one -> one.Value._2 [] @@ -2475,7 +2464,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.Reverse array array - SeqComposer.Array.createDelayedId delayedReverse + Composer.Array.createDelayedId delayedReverse [] let permute f (source:seq<_>) = @@ -2484,7 +2473,7 @@ namespace Microsoft.FSharp.Collections source |> toArray |> Array.permute f - SeqComposer.Array.createDelayedId delayedPermute + Composer.Array.createDelayedId delayedPermute [] let mapFold<'T,'State,'Result> (f: 'State -> 'T -> 'Result * 'State) acc source = @@ -2502,7 +2491,7 @@ namespace Microsoft.FSharp.Collections [] let except (itemsToExclude: seq<'T>) (source: seq<'T>) = checkNonNull "itemsToExclude" itemsToExclude - source |> seqFactory (SeqComposer.ExceptFactory itemsToExclude) + source |> seqFactory (Composer.ExceptFactory itemsToExclude) [] let chunkBySize chunkSize (source : seq<_>) = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index 92b49d572ae..27f44c0382a 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -13,48 +13,66 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = - module SeqComposer = - type ISeqComponent = - abstract OnComplete : int -> unit - abstract OnDispose : unit -> unit - - type ISeqPipeline = - abstract StopFurtherProcessing : int -> unit - - [] - type SeqConsumer<'T,'U> = - new : unit -> SeqConsumer<'T,'U> - abstract ProcessNext : input:'T -> bool - interface ISeqComponent - - [] - type Values<'a,'b> = - struct - new : a:'a * b:'b -> Values<'a,'b> - val mutable _1: 'a - val mutable _2: 'b - end - - [] - type Values<'a,'b,'c> = - struct - new : a:'a * b:'b * c:'c -> Values<'a,'b,'c> - val mutable _1: 'a - val mutable _2: 'b - val mutable _3: 'c - end - - [] - type Folder<'T,'U> = - class - inherit SeqConsumer<'T,'T> - new : init:'U -> Folder<'T,'U> - val mutable Value: 'U - end - - [] - type SeqEnumerable<'T> = - abstract member ForEach<'a when 'a :> SeqConsumer<'T,'T>> : f:(ISeqPipeline->'a) -> 'a + module Composer = + module Internal = + /// PipeIdx denotes the index of the element within the pipeline. 0 denotes the + /// source of the chain. + type PipeIdx = int + + /// ICompletionChaining is used to correctly handle cleaning up of the pipeline. A + /// base implementation is provided in Consumer, and should not be overwritten. Consumer + /// provides it's own OnComplete and OnDispose function which should be used to handle + /// a particular consumers cleanup. + type ICompletionChaining = + /// OnComplete is used to determine if the object has been processed correctly, + /// and possibly throw exceptions to denote incorrect application (i.e. such as a Take + /// operation which didn't have a source at least as large as was required). It is + /// not called in the case of an exception being thrown whilst the stream is still + /// being processed. + abstract OnComplete : PipeIdx -> unit + /// OnDispose is used to cleanup the stream. It is always called at the last operation + /// after the enumeration has completed. + abstract OnDispose : unit -> unit + + /// Consumer is the base class of all elements within the pipeline + [] + type Consumer<'T,'U> = + interface ICompletionChaining + new : unit -> Consumer<'T,'U> + abstract member ProcessNext : input:'T -> bool + abstract member OnComplete : PipeIdx -> unit + abstract member OnDispose : unit -> unit + + /// Values is a mutable struct. It can be embedded within the folder type + /// if two values are required for the calculation. + [] + type Values<'a,'b> = + new : a:'a * b:'b -> Values<'a,'b> + val mutable _1: 'a + val mutable _2: 'b + + /// Values is a mutable struct. It can be embedded within the folder type + /// if three values are required for the calculation. + [] + type Values<'a,'b,'c> = + new : a:'a * b:'b * c:'c -> Values<'a,'b,'c> + val mutable _1: 'a + val mutable _2: 'b + val mutable _3: 'c + + /// Folder is a base class to assist with fold-like operations. It's intended usage + /// is as a base class for an object expression that will be used from within + /// the ForEach function. + [] + type Folder<'T,'U> = + inherit Consumer<'T,'T> + new : init:'U -> Folder<'T,'U> + val mutable Value: 'U + + /// SeqEnumerable functions provide the enhance seq experience + [] + type SeqEnumerable<'T> = + abstract member ForEach<'a when 'a :> Consumer<'T,'T>> : f:((unit->unit)->'a) -> 'a /// Returns a new sequence that contains the cartesian product of the two input sequences. /// The first sequence. @@ -1247,7 +1265,7 @@ namespace Microsoft.FSharp.Collections /// /// Thrown when the input sequence is null. [] - val toComposer : source:seq<'T> -> SeqComposer.SeqEnumerable<'T> + val toComposer : source:seq<'T> -> Composer.Internal.SeqEnumerable<'T> /// Builds a list from the given collection. /// From 6d13d095dac3fe1af280217daa9dc2e35edee3ed Mon Sep 17 00:00:00 2001 From: liboz Date: Wed, 26 Oct 2016 22:09:06 -0400 Subject: [PATCH 24/59] seq.comparewith --- src/fsharp/FSharp.Core/seq.fs | 42 ++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 6617485d729..f2f3134bc9d 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -1826,22 +1826,38 @@ namespace Microsoft.FSharp.Collections [] let compareWith (f:'T -> 'T -> int) (source1 : seq<'T>) (source2: seq<'T>) = - checkNonNull "source1" source1 checkNonNull "source2" source2 - use e1 = source1.GetEnumerator() + use e2 = source2.GetEnumerator() let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let rec go () = - let e1ok = e1.MoveNext() - let e2ok = e2.MoveNext() - let c = if e1ok = e2ok then 0 else if e1ok then 1 else -1 - if c <> 0 then c else - if not e1ok || not e2ok then 0 - else - let c = f.Invoke(e1.Current, e2.Current) - if c <> 0 then c else - go () - go() + let mutable e2ok = Unchecked.defaultof + + source1 + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values<_,_>(false, 0)) with + override this.ProcessNext value = + e2ok <- e2.MoveNext() + if not e2ok then + this.Value._1 <- true + this.Value._2 <- 1 + halt () + else + let c = f.Invoke(value, e2.Current) + if c <> 0 then + this.Value._1 <- true + this.Value._2 <- c + halt () + Unchecked.defaultof + member this.OnComplete _ = + if not this.Value._1 then + e2ok <- e2.MoveNext() + if e2ok then + this.Value._2 <- -1 + else + this.Value._2 <- 0 + + }) + |> fun compare -> compare.Value._2 [] let ofList (source : 'T list) = From 438b1803dbfaaf45646fb8afd5a226edf9d43143 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 27 Oct 2016 08:49:21 +0200 Subject: [PATCH 25/59] More compact Seq.compareWith Bit faster on 64 bit, as don't need to access the ref of e2ok oops, type-o ! Minimalist exposure of factory infrastructire - made SeqEnumerable<> into an interface (ISeq<>) - made SeqComponentFactory<> into an interface (ISeqFactory<>) Renaming recommentations base on @rmunn feedback Commented strange Unchecked.default usage Partial move to Composer module In the Composer module we use ISeq rather than seq. An end goal could be be publicly expose this module for enhanced performancy. --- src/fsharp/FSharp.Core/seq.fs | 711 ++++++++++++++++++++------------- src/fsharp/FSharp.Core/seq.fsi | 18 +- 2 files changed, 438 insertions(+), 291 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index f2f3134bc9d..c2041123962 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -462,7 +462,7 @@ namespace Microsoft.FSharp.Collections abstract OnComplete : PipeIdx -> unit abstract OnDispose : unit -> unit - type IPipeline = + type IOutOfBand = abstract StopFurtherProcessing : PipeIdx -> unit [] @@ -516,9 +516,14 @@ namespace Microsoft.FSharp.Collections Value = init } - [] - type SeqEnumerable<'T>() = - abstract member ForEach<'a when 'a :> Consumer<'T,'T>> : f:((unit->unit)->'a) -> 'a + type ISeqFactory<'T,'U> = + abstract PipeIdx : PipeIdx + abstract Create<'V> : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> + + type ISeq<'T> = + inherit IEnumerable<'T> + abstract member Compose<'U> : (ISeqFactory<'T,'U>) -> ISeq<'U> + abstract member ForEach<'consumer when 'consumer :> Consumer<'T,'T>> : f:((unit->unit)->'consumer) -> 'consumer open Internal @@ -530,114 +535,137 @@ namespace Microsoft.FSharp.Collections // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality // is fixed with the compiler then these functions can be removed. + let inline upcastSeq (t:#ISeq<'T>) : ISeq<'T> = (# "" t : ISeq<'T> #) + let inline upcastFactory (t:#ISeqFactory<'T,'U>) : ISeqFactory<'T,'U> = (# "" t : ISeqFactory<'T,'U> #) let inline upcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) - let inline upcastISeqComponent (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) + let inline upcastICompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) type [] SeqComponentFactory<'T,'U> (pipeIdx:``PipeIdx?``) = - abstract Create<'V> : IPipeline -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> - new() = SeqComponentFactory<'T,'U> (emptyPipeIdx) - member __.PipeIdx = getPipeIdx pipeIdx + interface ISeqFactory<'T,'U> with + member __.PipeIdx = getPipeIdx pipeIdx + member __.Create _ _ _ = failwith "library implementation error: Create on base factory should not be called" - and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>, secondPipeIdx:PipeIdx) = + and ComposedFactory<'T,'U,'V> private (first:ISeqFactory<'T,'U>, second:ISeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = inherit SeqComponentFactory<'T,'V> (makePipeIdx secondPipeIdx) - override this.Create<'W> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'V,'W>) : Consumer<'T,'W> = - first.Create result pipeIdx (second.Create result (makePipeIdx secondPipeIdx) next) + interface ISeqFactory<'T,'V> with + member this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'V,'W>) : Consumer<'T,'W> = + first.Create outOfBand pipeIdx (second.Create outOfBand (makePipeIdx secondPipeIdx) next) - static member Combine (first:SeqComponentFactory<'T,'U>) (second:SeqComponentFactory<'U,'V>) : SeqComponentFactory<'T,'V> = - upcast ComposedFactory(first, second, first.PipeIdx+1) + static member Combine (first:ISeqFactory<'T,'U>) (second:ISeqFactory<'U,'V>) : ISeqFactory<'T,'V> = + ComposedFactory(first, second, first.PipeIdx+1) |> Helpers.upcastFactory and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) + interface ISeqFactory<'T,'U> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) and DistinctFactory<'T when 'T: equality> () = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) and FilterFactory<'T> (filter:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = - match next with - | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter - | _ -> upcast Filter (filter, next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = + match next with + | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter + | _ -> upcast Filter (filter, next) and IdentityFactory<'T> () = inherit SeqComponentFactory<'T,'T> () static let singleton = IdentityFactory<'T>() - override __.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next - static member IdentityFactory = singleton + interface ISeqFactory<'T,'T> with + member __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next + static member Instance = singleton and MapFactory<'T,'U> (map:'T->'U) = inherit SeqComponentFactory<'T,'U> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = - match next with - | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map - | _ -> upcast Map<_,_,_> (map, next) + interface ISeqFactory<'T,'U> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = + match next with + | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map + | _ -> upcast Map<_,_,_> (map, next) and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'First,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, outOfBand, next, getPipeIdx pipeIdx) and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = inherit SeqComponentFactory<'Second,'U> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'Second,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, outOfBand, next, getPipeIdx pipeIdx) and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = inherit SeqComponentFactory<'First,'U> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'First,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, outOfBand, next, getPipeIdx pipeIdx) and MapiFactory<'T,'U> (mapi:int->'T->'U) = inherit SeqComponentFactory<'T,'U> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Mapi (mapi, next) + interface ISeqFactory<'T,'U> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Mapi (mapi, next) and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'First,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, outOfBand, next, getPipeIdx pipeIdx) and PairwiseFactory<'T> () = inherit SeqComponentFactory<'T,'T*'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) + interface ISeqFactory<'T,'T*'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) and ScanFactory<'T,'State> (folder:'State->'T->'State, initialState:'State) = inherit SeqComponentFactory<'T,'State> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) + interface ISeqFactory<'T,'State> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) and SkipFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, next) and SkipWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) and TakeWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, outOfBand, next, getPipeIdx pipeIdx) and TakeFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, outOfBand, next, getPipeIdx pipeIdx) and TailFactory<'T> () = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) and TruncateFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, getPipeIdx pipeIdx) and [] SeqComponent<'T,'U> (next:ICompletionChaining) = inherit Consumer<'T,'U>() @@ -731,7 +759,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = Helpers.avoidTailCall (next.ProcessNext (map input)) - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () @@ -741,13 +769,13 @@ namespace Microsoft.FSharp.Collections if input2.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) else - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx false override __.OnDispose () = input2.Dispose () - and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = inherit SeqComponent<'Second,'V>(next) let input1 = enumerable1.GetEnumerator () @@ -757,13 +785,13 @@ namespace Microsoft.FSharp.Collections if input1.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) else - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx false override __.OnDispose () = input1.Dispose () - and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () @@ -774,7 +802,7 @@ namespace Microsoft.FSharp.Collections if input2.MoveNext () && input3.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) else - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx false override __.OnDispose () = @@ -801,7 +829,7 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) - and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = inherit SeqComponent<'First,'V>(next) let mutable idx = 0 @@ -813,7 +841,7 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) else - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx false override __.OnDispose () = @@ -885,8 +913,8 @@ namespace Microsoft.FSharp.Collections else Helpers.avoidTailCall (next.ProcessNext input) - and Take<'T,'V> (takeCount:int, result:IPipeline, next:Consumer<'T,'V>, pipelineIdx:int) = - inherit Truncate<'T, 'V>(takeCount, result, next, pipelineIdx) + and Take<'T,'V> (takeCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipelineIdx:int) = + inherit Truncate<'T, 'V>(takeCount, outOfBand, next, pipelineIdx) override this.OnComplete terminatingIdx = if terminatingIdx < pipelineIdx && this.Count < takeCount then @@ -894,14 +922,14 @@ namespace Microsoft.FSharp.Collections invalidOpFmt "tried to take {0} {1} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - and TakeWhile<'T,'V> (predicate:'T->bool, result:IPipeline, next:Consumer<'T,'V>, pipeIdx:int) = + and TakeWhile<'T,'V> (predicate:'T->bool, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = if predicate input then Helpers.avoidTailCall (next.ProcessNext input) else - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx false and Tail<'T, 'V> (next:Consumer<'T,'V>) = @@ -920,7 +948,7 @@ namespace Microsoft.FSharp.Collections if first then invalidArg "source" (SR.GetString(SR.notEnoughElements)) - and Truncate<'T,'V> (truncateCount:int, result:IPipeline, next:Consumer<'T,'V>, pipeIdx:int) = + and Truncate<'T,'V> (truncateCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = inherit SeqComponent<'T,'V>(next) let mutable count = 0 @@ -931,10 +959,10 @@ namespace Microsoft.FSharp.Collections if count < truncateCount then count <- count + 1 if count = truncateCount then - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx next.ProcessNext input else - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx false type SeqProcessNextStates = @@ -949,7 +977,7 @@ namespace Microsoft.FSharp.Collections member val SeqState = SeqProcessNextStates.NotStarted with get, set member __.HaltedIdx = haltedIdx - interface IPipeline with + interface IOutOfBand with member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx // SetResult<> is used at the end of the chain of SeqComponents to assign the final value @@ -960,35 +988,35 @@ namespace Microsoft.FSharp.Collections result.Current <- input true - type Pipeline() = + type OutOfBand() = let mutable haltedIdx = 0 - interface IPipeline with member x.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx + interface IOutOfBand with member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx member __.HaltedIdx = haltedIdx module ForEach = - let enumerable (enumerable:IEnumerable<'T>) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = + let enumerable (enumerable:IEnumerable<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = use enumerator = enumerable.GetEnumerator () - while (pipeline.HaltedIdx = 0) && (enumerator.MoveNext ()) do + while (outOfBand.HaltedIdx = 0) && (enumerator.MoveNext ()) do consumer.ProcessNext enumerator.Current |> ignore - let array (array:array<'T>) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = + let array (array:array<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = let mutable idx = 0 - while (pipeline.HaltedIdx = 0) && (idx < array.Length) do + while (outOfBand.HaltedIdx = 0) && (idx < array.Length) do consumer.ProcessNext array.[idx] |> ignore idx <- idx + 1 - let list (alist:list<'T>) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = + let list (alist:list<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = let rec iterate lst = - match pipeline.HaltedIdx, lst with + match outOfBand.HaltedIdx, lst with | 0, hd :: tl -> consumer.ProcessNext hd |> ignore iterate tl | _ -> () iterate alist - let unfold (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = + let unfold (generator:'S->option<'T*'S>) state (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = let rec iterate current = - match pipeline.HaltedIdx, generator current with + match outOfBand.HaltedIdx, generator current with | 0, Some (item, next) -> consumer.ProcessNext item |> ignore iterate next @@ -1001,11 +1029,11 @@ namespace Microsoft.FSharp.Collections | :? SeqComponent<'T,'U> as c -> c.Skipping | _ -> fun () -> false - let init f (terminatingIdx:int) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = + let init f (terminatingIdx:int) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = let mutable idx = -1 let isSkipping = makeIsSkipping consumer let mutable maybeSkipping = true - while (pipeline.HaltedIdx = 0) && (idx < terminatingIdx) do + while (outOfBand.HaltedIdx = 0) && (idx < terminatingIdx) do if maybeSkipping then maybeSkipping <- isSkipping () @@ -1014,16 +1042,16 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 - let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:SeqComponentFactory<'T,'U>) executeOn = - let pipeline = Pipeline() - let result = f (fun () -> (pipeline:>IPipeline).StopFurtherProcessing (current.PipeIdx+1)) + let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:ISeqFactory<'T,'U>) executeOn = + let pipeline = OutOfBand() + let result = f (fun () -> (pipeline:>IOutOfBand).StopFurtherProcessing (current.PipeIdx+1)) let consumer = current.Create pipeline emptyPipeIdx result try executeOn pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete pipeline.HaltedIdx + (Helpers.upcastICompletionChaining consumer).OnComplete pipeline.HaltedIdx result finally - (Helpers.upcastISeqComponent consumer).OnDispose () + (Helpers.upcastICompletionChaining consumer).OnDispose () module Enumerable = type Empty<'T>() = @@ -1062,9 +1090,9 @@ namespace Microsoft.FSharp.Collections | _ -> failwith "library implementation error: all states should have been handled" and [] EnumerableBase<'T> () = - inherit SeqEnumerable<'T>() + let derivedClassShouldImplement () = + failwith "library implementation error: derived class should implement (should be abstract)" - abstract member Compose<'U> : (SeqComponentFactory<'T,'U>) -> IEnumerable<'U> abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> default this.Append source = Helpers.upcastEnumerable (AppendEnumerable [this; source]) @@ -1076,8 +1104,11 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumeratorNonGeneric genericEnumerator interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = failwith "library implementation error: derived class should implement (should be abstract)" + member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement () + interface ISeq<'T> with + member __.Compose _ = derivedClassShouldImplement () + member __.ForEach _ = derivedClassShouldImplement () and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = inherit EnumeratorBase<'U>(result, seqComponent) @@ -1090,7 +1121,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete result.HaltedIdx + (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1103,9 +1134,9 @@ namespace Microsoft.FSharp.Collections try source.Dispose () finally - (Helpers.upcastISeqComponent seqComponent).OnDispose () + (Helpers.upcastICompletionChaining seqComponent).OnDispose () - and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqComponentFactory<'T,'U>) = + and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:ISeqFactory<'T,'U>) = inherit EnumerableBase<'U>() interface IEnumerable<'U> with @@ -1113,11 +1144,12 @@ namespace Microsoft.FSharp.Collections let result = Result<'U> () Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) - override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) + interface ISeq<'U> with + member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + Helpers.upcastSeq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) - override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.enumerable enumerable) + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.enumerable enumerable) and ConcatEnumerator<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = let mutable state = SeqProcessNextStates.NotStarted @@ -1162,14 +1194,15 @@ namespace Microsoft.FSharp.Collections member this.GetEnumerator () : IEnumerator<'T> = Helpers.upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) - override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = - Helpers.upcastEnumerable (Enumerable<'T,'V>(this, next)) - override this.Append source = Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) - override this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable this) + interface ISeq<'T> with + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + Helpers.upcastSeq (Enumerable<'T,'V>(this, next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) and ConcatEnumerable<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = inherit EnumerableBase<'T>() @@ -1178,14 +1211,37 @@ namespace Microsoft.FSharp.Collections member this.GetEnumerator () : IEnumerator<'T> = Helpers.upcastEnumerator (new ConcatEnumerator<_,_> (sources)) - override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = - Helpers.upcastEnumerable (Enumerable<'T,'V>(this, next)) + interface ISeq<'T> with + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + Helpers.upcastSeq (Enumerable<'T,'V>(this, next)) - override this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable this) + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) let create enumerable current = - Helpers.upcastEnumerable (Enumerable(enumerable, current)) + Helpers.upcastSeq (Enumerable(enumerable, current)) + + module EmptyEnumerable = + type Enumerable<'T> () = + inherit Enumerable.EnumerableBase<'T>() + + static let singleton = Enumerable<'T>() :> ISeq<'T> + static member Instance = singleton + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>() + + override this.Append source = + Helpers.upcastEnumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) + + interface ISeq<'T> with + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + Helpers.upcastSeq (Enumerable.Enumerable<'T,'V>(this, next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) + + module Array = type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = @@ -1211,7 +1267,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete result.HaltedIdx + (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1219,7 +1275,7 @@ namespace Microsoft.FSharp.Collections initMoveNext () moveNext () - type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqComponentFactory<'T,'U>) = + type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:ISeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with @@ -1227,23 +1283,24 @@ namespace Microsoft.FSharp.Collections let result = Result<'U> () Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) + interface ISeq<'U> with + member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + Helpers.upcastSeq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) - override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.array (delayedArray ())) + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.array (delayedArray ())) - let createDelayed (delayedArray:unit->array<'T>) (current:SeqComponentFactory<'T,'U>) = - Helpers.upcastEnumerable (Enumerable(delayedArray, current)) + let createDelayed (delayedArray:unit->array<'T>) (current:ISeqFactory<'T,'U>) = + Helpers.upcastSeq (Enumerable(delayedArray, current)) - let create (array:array<'T>) (current:SeqComponentFactory<'T,'U>) = + let create (array:array<'T>) (current:ISeqFactory<'T,'U>) = createDelayed (fun () -> array) current let createDelayedId (delayedArray:unit -> array<'T>) = - createDelayed delayedArray IdentityFactory.IdentityFactory + createDelayed delayedArray IdentityFactory.Instance let createId (array:array<'T>) = - create array IdentityFactory.IdentityFactory + create array IdentityFactory.Instance module List = type Enumerator<'T,'U>(alist:list<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = @@ -1261,7 +1318,7 @@ namespace Microsoft.FSharp.Collections moveNext tail | _ -> result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete result.HaltedIdx + (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1269,7 +1326,7 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext list - type Enumerable<'T,'U>(alist:list<'T>, current:SeqComponentFactory<'T,'U>) = + type Enumerable<'T,'U>(alist:list<'T>, current:ISeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with @@ -1277,23 +1334,24 @@ namespace Microsoft.FSharp.Collections let result = Result<'U> () Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) + interface ISeq<'U> with + member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + Helpers.upcastSeq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) - override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.list alist) + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.list alist) let create alist current = - Helpers.upcastEnumerable (Enumerable(alist, current)) + Helpers.upcastSeq (Enumerable(alist, current)) module Unfold = - type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, signal:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) + type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let mutable current = state let rec moveNext () = - match signal.HaltedIdx, generator current with + match result.HaltedIdx, generator current with | 0, Some (item, nextState) -> current <- nextState if seqComponent.ProcessNext item then @@ -1304,10 +1362,10 @@ namespace Microsoft.FSharp.Collections interface IEnumerator with member __.MoveNext () = - signal.SeqState <- SeqProcessNextStates.InProcess + result.SeqState <- SeqProcessNextStates.InProcess moveNext () - type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqComponentFactory<'T,'U>) = + type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:ISeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with @@ -1315,11 +1373,12 @@ namespace Microsoft.FSharp.Collections let result = Result<'U> () Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + interface ISeq<'U> with + member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + Helpers.upcastSeq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) - override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.unfold generator state) + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.unfold generator state) module Init = // The original implementation of "init" delayed the calculation of Current, and so it was possible @@ -1343,8 +1402,8 @@ namespace Microsoft.FSharp.Collections else System.Int32.MaxValue - type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:Consumer<'T,'U>, signal:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) + type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let isSkipping = ForEach.makeIsSkipping seqComponent @@ -1356,7 +1415,7 @@ namespace Microsoft.FSharp.Collections let mutable idx = -1 let rec moveNext () = - if (signal.HaltedIdx = 0) && idx < terminatingIdx then + if (result.HaltedIdx = 0) && idx < terminatingIdx then idx <- idx + 1 if maybeSkipping then @@ -1370,19 +1429,19 @@ namespace Microsoft.FSharp.Collections true else moveNext () - elif (signal.HaltedIdx = 0) && idx = System.Int32.MaxValue then + elif (result.HaltedIdx = 0) && idx = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) else - signal.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete signal.HaltedIdx + result.SeqState <- SeqProcessNextStates.Finished + (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with member __.MoveNext () = - signal.SeqState <- SeqProcessNextStates.InProcess + result.SeqState <- SeqProcessNextStates.InProcess moveNext () - type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqComponentFactory<'T,'U>) = + type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:ISeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with @@ -1390,12 +1449,13 @@ namespace Microsoft.FSharp.Collections let result = Result<'U> () Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + interface ISeq<'U> with + member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + Helpers.upcastSeq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) - override this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = - let terminatingIdx = getTerminatingIdx count - ForEach.execute createResult current (ForEach.init f terminatingIdx) + member this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = + let terminatingIdx = getTerminatingIdx count + ForEach.execute createResult current (ForEach.init f terminatingIdx) let upto lastOption f = match lastOption with @@ -1457,11 +1517,172 @@ namespace Microsoft.FSharp.Collections // in the way presented, but it's possible. upto (if count.HasValue then Some (count.Value-1) else None) f - override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = - Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) + interface ISeq<'T> with + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + Helpers.upcastSeq (Enumerable<'T,'V>(count, f, next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (Helpers.upcastEnumerable this)) + + open RuntimeHelpers + + [] + let toComposer (source:seq<'T>) : ISeq<'T> = + checkNonNull "source" source + match source with + | :? ISeq<'T> as s -> s + | :? array<'T> as a -> Helpers.upcastSeq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) + | :? list<'T> as a -> Helpers.upcastSeq (List.Enumerable(a, IdentityFactory.Instance)) + | _ -> Helpers.upcastSeq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) + + let inline foreach f (source:ISeq<_>) = + source.ForEach f + + let inline compose factory (source:ISeq<'T>) = + source.Compose factory + + [] + let empty<'T> = EmptyEnumerable.Enumerable<'T>.Instance + + [] + let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> = + Helpers.upcastSeq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) + + [] + let initInfinite<'T> (f:int->'T) : ISeq<'T> = + Helpers.upcastSeq (new Init.EnumerableDecider<'T>(Nullable (), f)) + + [] + let init<'T> (count:int) (f:int->'T) : ISeq<'T> = + if count < 0 then invalidArgInputMustBeNonNegative "count" count + elif count = 0 then empty else + Helpers.upcastSeq (new Init.EnumerableDecider<'T>(Nullable count, f)) + + [] + let iter f (source:ISeq<'T>) = + source + |> foreach (fun _ -> + { new Consumer<'T,'T> () with + override this.ProcessNext value = + f value + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> ignore + + [] + let tryItem i (source:ISeq<'T>) = + if i < 0 then None else + source + |> foreach (fun halt -> + { new Folder<'T, Values>> (Values<_,_> (0, None)) with + override this.ProcessNext value = + if this.Value._1 = i then + this.Value._2 <- Some value + halt () + else + this.Value._1 <- this.Value._1 + 1 + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun item -> item.Value._2 + + [] + let iteri f (source:ISeq<'T>) = + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f + + source + |> foreach (fun _ -> + { new Folder<'T, int> (0) with + override this.ProcessNext value = + f.Invoke(this.Value, value) + this.Value <- this.Value + 1 + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> ignore + + [] + let exists f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, bool> (false) with + override this.ProcessNext value = + if f value then + this.Value <- true + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun exists -> exists.Value + + [] + let inline contains element (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, bool> (false) with + override this.ProcessNext value = + if element = value then + this.Value <- true + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun contains -> contains.Value + + [] + let forall f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, bool> (true) with + override this.ProcessNext value = + if not (f value) then + this.Value <- false + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun forall -> forall.Value + + [] + let filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = + source + |> compose (FilterFactory f) + + [] + let map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = + source + |> compose (MapFactory f) + + [] + let mapi f source = + source + |> compose (MapiFactory f) + + [] + let choose f source = + source + |> compose (ChooseFactory f) + + [] + let indexed source = + source + |> compose (MapiFactory (fun i x -> i,x)) + + [] + let tryPick f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, Option<'U>> (None) with + override this.ProcessNext value = + match f value with + | (Some _) as some -> + this.Value <- some + halt () + | None -> () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun pick -> pick.Value + + [] + let tryFind f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, Option<'T>> (None) with + override this.ProcessNext value = + if f value then + this.Value <- Some value + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun find -> find.Value - override this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable (Helpers.upcastEnumerable this)) #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions @@ -1474,48 +1695,36 @@ namespace Microsoft.FSharp.Collections let inline indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) [] - let toComposer (source:seq<'T>): Composer.Internal.SeqEnumerable<'T> = - checkNonNull "source" source - match source with - | :? Composer.Enumerable.EnumerableBase<'T> as s -> upcast s - | :? array<'T> as a -> upcast Composer.Array.Enumerable((fun () -> a), Composer.IdentityFactory.IdentityFactory) - | :? list<'T> as a -> upcast Composer.List.Enumerable(a, Composer.IdentityFactory.IdentityFactory) - | _ -> upcast Composer.Enumerable.Enumerable<'T,'T>(source, Composer.IdentityFactory.IdentityFactory) + let toComposer (source:seq<'T>): Composer.Internal.ISeq<'T> = + Composer.toComposer source let inline foreach f (source:seq<_>) = - source - |> toComposer - |> fun composer -> composer.ForEach f + Composer.foreach f (toComposer source) [] let delay f = mkDelayedSeq f [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> = - Composer.Helpers.upcastEnumerable (new Composer.Unfold.Enumerable<'T,'T,'State>(generator, state, Composer.IdentityFactory.IdentityFactory)) + Composer.unfold generator state + |> Composer.Helpers.upcastEnumerable [] let empty<'T> = (EmptyEnumerable :> seq<'T>) [] let initInfinite<'T> (f:int->'T) : IEnumerable<'T> = - Composer.Helpers.upcastEnumerable (new Composer.Init.EnumerableDecider<'T>(Nullable (), f)) + Composer.initInfinite f + |> Composer.Helpers.upcastEnumerable [] let init<'T> (count:int) (f:int->'T) : IEnumerable<'T> = - if count < 0 then invalidArgInputMustBeNonNegative "count" count - elif count = 0 then empty else - Composer.Helpers.upcastEnumerable (new Composer.Init.EnumerableDecider<'T>(Nullable count, f)) + Composer.init count f + |> Composer.Helpers.upcastEnumerable [] let iter f (source : seq<'T>) = - source - |> foreach (fun _ -> - { new Composer.Internal.Consumer<'T,'T> () with - override this.ProcessNext value = - f value - Unchecked.defaultof }) - |> ignore + Composer.iter f (toComposer source) [] let item i (source : seq<'T>) = @@ -1525,73 +1734,27 @@ namespace Microsoft.FSharp.Collections IEnumerator.nth i e [] - let tryItem i (source : seq<'T>) = - if i < 0 then None else - source - |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values>> (Composer.Internal.Values<_, _> (0, None)) with - override this.ProcessNext value = - if this.Value._1 = i then - this.Value._2 <- Some value - halt () - else - this.Value._1 <- this.Value._1 + 1 - Unchecked.defaultof }) - |> fun item -> item.Value._2 + let tryItem i (source:seq<'T>) = + Composer.tryItem i (toComposer source) [] let nth i (source : seq<'T>) = item i source [] - let iteri f (source : seq<'T>) = - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - source - |> foreach (fun _ -> - { new Composer.Internal.Folder<'T, int> (0) with - override this.ProcessNext value = - f.Invoke(this.Value, value) - this.Value <- this.Value + 1 - Unchecked.defaultof }) - |> ignore + let iteri f (source:seq<'T>) = + Composer.iteri f (toComposer source) [] - let exists f (source : seq<'T>) = - source - |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, bool> (false) with - override this.ProcessNext value = - if f value then - this.Value <- true - halt () - Unchecked.defaultof - }) - |> fun exists -> exists.Value + let exists f (source:seq<'T>) = + Composer.exists f (toComposer source) [] - let inline contains element (source : seq<'T>) = - source - |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, bool> (false) with - override this.ProcessNext value = - if element = value then - this.Value <- true - halt () - Unchecked.defaultof - }) - |> fun contains -> contains.Value + let inline contains element (source:seq<'T>) = + Composer.contains element (toComposer source) [] - let forall f (source : seq<'T>) = - source - |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, bool> (true) with - override this.ProcessNext value = - if not (f value) then - this.Value <- false - halt () - Unchecked.defaultof - }) - |> fun forall -> forall.Value + let forall f (source:seq<'T>) = + Composer.forall f (toComposer source) [] let iter2 f (source1 : seq<_>) (source2 : seq<_>) = @@ -1625,25 +1788,28 @@ namespace Microsoft.FSharp.Collections let private seqFactory createSeqComponent (source:seq<'T>) = checkNonNull "source" source match source with - | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Compose createSeqComponent - | :? array<'T> as a -> Composer.Array.create a createSeqComponent - | :? list<'T> as a -> Composer.List.create a createSeqComponent - | _ -> Composer.Enumerable.create source createSeqComponent + | :? Composer.Internal.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose createSeqComponent) + | :? array<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.Array.create a createSeqComponent) + | :? list<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.List.create a createSeqComponent) + | _ -> Composer.Helpers.upcastEnumerable (Composer.Enumerable.create source createSeqComponent) [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = - source |> seqFactory (Composer.FilterFactory f) + Composer.filter f (toComposer source) + |> Composer.Helpers.upcastEnumerable [] let where f source = filter f source [] let map<'T,'U> (f:'T->'U) (source:seq<'T>) : seq<'U> = - source |> seqFactory (Composer.MapFactory f) + Composer.map f (toComposer source) + |> Composer.Helpers.upcastEnumerable [] let mapi f source = - source |> seqFactory (Composer.MapiFactory f) + Composer.mapi f (toComposer source) + |> Composer.Helpers.upcastEnumerable [] let mapi2 f source1 source2 = @@ -1654,7 +1820,7 @@ namespace Microsoft.FSharp.Collections let map2<'T,'U,'V> (f:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = checkNonNull "source1" source1 match source1 with - | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Compose (Composer.Map2FirstFactory (f, source2)) + | :? Composer.Internal.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose (Composer.Map2FirstFactory (f, source2))) | _ -> source2 |> seqFactory (Composer.Map2SecondFactory (f, source1)) [] @@ -1664,12 +1830,14 @@ namespace Microsoft.FSharp.Collections source1 |> seqFactory (Composer.Map3Factory (f, source2, source3)) [] - let choose f source = - source |> seqFactory (Composer.ChooseFactory f) + let choose f source = + Composer.choose f (toComposer source) + |> Composer.Helpers.upcastEnumerable [] let indexed source = - source |> seqFactory (Composer.MapiFactory (fun i x -> i,x) ) + Composer.indexed (toComposer source) + |> Composer.Helpers.upcastEnumerable [] let zip source1 source2 = @@ -1686,17 +1854,7 @@ namespace Microsoft.FSharp.Collections [] let tryPick f (source : seq<'T>) = - source - |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Option<'U>> (None) with - override this.ProcessNext value = - match f value with - | (Some _) as some -> - this.Value <- some - halt () - | None -> () - Unchecked.defaultof }) - |> fun pick -> pick.Value + Composer.tryPick f (toComposer source) [] let pick f source = @@ -1706,15 +1864,7 @@ namespace Microsoft.FSharp.Collections [] let tryFind f (source : seq<'T>) = - source - |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Option<'T>> (None) with - override this.ProcessNext value = - if f value then - this.Value <- Some value - halt () - Unchecked.defaultof }) - |> fun find -> find.Value + Composer.tryFind f (toComposer source) [] let find f source = @@ -1768,7 +1918,7 @@ namespace Microsoft.FSharp.Collections { new Composer.Internal.Folder<'T,'State> (x) with override this.ProcessNext value = this.Value <- f.Invoke (this.Value, value) - Unchecked.defaultof }) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun folded -> folded.Value [] @@ -1800,7 +1950,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- value else this.Value._2 <- f.Invoke (this.Value._2, value) - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._1 then @@ -1830,34 +1980,24 @@ namespace Microsoft.FSharp.Collections use e2 = source2.GetEnumerator() let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let mutable e2ok = Unchecked.defaultof source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values<_,_>(false, 0)) with + { new Composer.Internal.Folder<'T,int> (0) with override this.ProcessNext value = - e2ok <- e2.MoveNext() - if not e2ok then - this.Value._1 <- true - this.Value._2 <- 1 + if not (e2.MoveNext()) then + this.Value <- 1 halt () else - let c = f.Invoke(value, e2.Current) + let c = f.Invoke (value, e2.Current) if c <> 0 then - this.Value._1 <- true - this.Value._2 <- c + this.Value <- c halt () - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = - if not this.Value._1 then - e2ok <- e2.MoveNext() - if e2ok then - this.Value._2 <- -1 - else - this.Value._2 <- 0 - - }) - |> fun compare -> compare.Value._2 + if this.Value = 0 && e2.MoveNext() then + this.Value <- -1 }) + |> fun compare -> compare.Value [] let ofList (source : 'T list) = @@ -1872,7 +2012,7 @@ namespace Microsoft.FSharp.Collections [] let ofArray (source : 'T array) = checkNonNull "source" source - Composer.Array.createId source + Composer.Helpers.upcastEnumerable (Composer.Array.createId source) [] let toArray (source : seq<'T>) = @@ -1967,8 +2107,7 @@ namespace Microsoft.FSharp.Collections halt () else this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof - }) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun tried -> tried.Value._1 [] @@ -2141,7 +2280,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceBy keyf array array - Composer.Array.createDelayedId delayedSort + Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedSort) [] let sort source = @@ -2150,7 +2289,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlace array array - Composer.Array.createDelayedId delayedSort + Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedSort) [] let sortWith f source = @@ -2159,7 +2298,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceWith f array array - Composer.Array.createDelayedId delayedSort + Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedSort) [] let inline sortByDescending keyf source = @@ -2213,7 +2352,7 @@ namespace Microsoft.FSharp.Collections { new Composer.Internal.Folder<'a,'a> (LanguagePrimitives.GenericZero) with override this.ProcessNext value = this.Value <- Checked.(+) this.Value value - Unchecked.defaultof }) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun sum -> sum.Value [] @@ -2223,7 +2362,7 @@ namespace Microsoft.FSharp.Collections { new Composer.Internal.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with override this.ProcessNext value = this.Value <- Checked.(+) this.Value (f value) - Unchecked.defaultof }) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun sum -> sum.Value [] @@ -2234,7 +2373,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 value this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._2 = 0 then @@ -2249,7 +2388,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 (f value) this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._2 = 0 then @@ -2267,7 +2406,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- value elif value < this.Value._2 then this.Value._2 <- value - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._1 then @@ -2290,7 +2429,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- valueU this.Value._3 <- value | _ -> () - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._1 then @@ -2325,7 +2464,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- value elif value > this.Value._2 then this.Value._2 <- value - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._1 then @@ -2348,7 +2487,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- valueU this.Value._3 <- value | _ -> () - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._1 then @@ -2417,7 +2556,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = this.Value <- Some value halt () - Unchecked.defaultof }) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun head -> head.Value [] @@ -2439,7 +2578,7 @@ namespace Microsoft.FSharp.Collections if this.Value._1 then this.Value._1 <- false this.Value._2 <- value - Unchecked.defaultof }) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun tried -> if tried.Value._1 then None @@ -2464,7 +2603,7 @@ namespace Microsoft.FSharp.Collections else this.Value._3 <- true halt () - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._1 then @@ -2480,7 +2619,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.Reverse array array - Composer.Array.createDelayedId delayedReverse + Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedReverse) [] let permute f (source:seq<_>) = @@ -2489,7 +2628,7 @@ namespace Microsoft.FSharp.Collections source |> toArray |> Array.permute f - Composer.Array.createDelayedId delayedPermute + Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedPermute) [] let mapFold<'T,'State,'Result> (f: 'State -> 'T -> 'Result * 'State) acc source = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index 27f44c0382a..94dbb8bcc1a 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -18,6 +18,7 @@ namespace Microsoft.FSharp.Collections /// PipeIdx denotes the index of the element within the pipeline. 0 denotes the /// source of the chain. type PipeIdx = int + type ``PipeIdx?`` = Nullable /// ICompletionChaining is used to correctly handle cleaning up of the pipeline. A /// base implementation is provided in Consumer, and should not be overwritten. Consumer @@ -34,6 +35,9 @@ namespace Microsoft.FSharp.Collections /// after the enumeration has completed. abstract OnDispose : unit -> unit + type IOutOfBand = + abstract StopFurtherProcessing : PipeIdx -> unit + /// Consumer is the base class of all elements within the pipeline [] type Consumer<'T,'U> = @@ -69,10 +73,14 @@ namespace Microsoft.FSharp.Collections new : init:'U -> Folder<'T,'U> val mutable Value: 'U - /// SeqEnumerable functions provide the enhance seq experience - [] - type SeqEnumerable<'T> = - abstract member ForEach<'a when 'a :> Consumer<'T,'T>> : f:((unit->unit)->'a) -> 'a + type ISeqFactory<'T,'U> = + abstract member Create : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> + abstract member PipeIdx : PipeIdx + + type ISeq<'T> = + inherit System.Collections.Generic.IEnumerable<'T> + abstract member Compose : ISeqFactory<'T,'U> -> ISeq<'U> + abstract member ForEach : f:((unit -> unit) -> 'a) -> 'a when 'a :> Consumer<'T,'T> /// Returns a new sequence that contains the cartesian product of the two input sequences. /// The first sequence. @@ -1265,7 +1273,7 @@ namespace Microsoft.FSharp.Collections /// /// Thrown when the input sequence is null. [] - val toComposer : source:seq<'T> -> Composer.Internal.SeqEnumerable<'T> + val toComposer : source:seq<'T> -> Composer.Internal.ISeq<'T> /// Builds a list from the given collection. /// From 0594870c8c31878a90ee853ff65b9a9fc6630233 Mon Sep 17 00:00:00 2001 From: liboz Date: Sat, 29 Oct 2016 22:26:16 -0400 Subject: [PATCH 26/59] Seq.item/iter2/iteri2/fold2/forall2/exists2 --- src/fsharp/FSharp.Core/seq.fs | 131 +++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 48 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index c2041123962..386a956a87c 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -56,20 +56,6 @@ namespace Microsoft.FSharp.Collections let Empty<'T> () = (new EmptyEnumerator<'T>() :> IEnumerator<'T>) - let rec tryItem index (e : IEnumerator<'T>) = - if not (e.MoveNext()) then None - elif index = 0 then Some(e.Current) - else tryItem (index-1) e - - let rec nth index (e : IEnumerator<'T>) = - if not (e.MoveNext()) then - let shortBy = index + 1 - invalidArgFmt "index" - "{0}\nseq was short by {1} {2}" - [|SR.GetString SR.notEnoughElements; shortBy; (if shortBy = 1 then "element" else "elements")|] - if index = 0 then e.Current - else nth (index-1) e - let readAndClear r = lock r (fun () -> match !r with None -> None | Some _ as res -> r := None; res) @@ -1728,10 +1714,26 @@ namespace Microsoft.FSharp.Collections [] let item i (source : seq<'T>) = - checkNonNull "source" source - if i < 0 then invalidArgInputMustBeNonNegative "index" i - use e = source.GetEnumerator() - IEnumerator.nth i e + if i < 0 then invalidArgInputMustBeNonNegative "index" i else + source + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values<_,_,_> (0, false, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 = i then + this.Value._2 <- true + this.Value._3 <- value + halt () + else + this.Value._1 <- this.Value._1 + 1 + Unchecked.defaultof<_> (* return value unsed in ForEach context *) + override this.OnComplete _ = + if not this.Value._2 then + let index = i - this.Value._1 + 1 + invalidArgFmt "index" + "{0}\nseq was short by {1} {2}" + [|SR.GetString SR.notEnoughElements; index; (if index=1 then "element" else "elements")|] + }) + |> fun item -> item.Value._3 [] let tryItem i (source:seq<'T>) = @@ -1758,25 +1760,40 @@ namespace Microsoft.FSharp.Collections [] let iter2 f (source1 : seq<_>) (source2 : seq<_>) = - checkNonNull "source1" source1 checkNonNull "source2" source2 - use e1 = source1.GetEnumerator() + use e2 = source2.GetEnumerator() let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - while (e1.MoveNext() && e2.MoveNext()) do - f.Invoke(e1.Current, e2.Current) + + source1 + |> foreach (fun halt -> + { new Composer.Internal.Folder<_,_> () with + override this.ProcessNext value = + if (e2.MoveNext()) then + f.Invoke(value, e2.Current) + else + halt() + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> ignore [] let iteri2 f (source1 : seq<_>) (source2 : seq<_>) = - checkNonNull "source1" source1 checkNonNull "source2" source2 - use e1 = source1.GetEnumerator() + use e2 = source2.GetEnumerator() let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f) - let mutable i = 0 - while (e1.MoveNext() && e2.MoveNext()) do - f.Invoke(i, e1.Current, e2.Current) - i <- i + 1 + + source1 + |> foreach (fun halt -> + { new Composer.Internal.Folder<_,int> (0) with + override this.ProcessNext value = + if (e2.MoveNext()) then + f.Invoke(this.Value, value, e2.Current) + this.Value <- this.Value + 1 + else + halt() + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> ignore // Build an IEnumerble by wrapping/transforming iterators as they get generated. let revamp f (ie : seq<_>) = mkSeq (fun () -> f (ie.GetEnumerator())) @@ -1923,19 +1940,21 @@ namespace Microsoft.FSharp.Collections [] let fold2<'T1,'T2,'State> f (state:'State) (source1: seq<'T1>) (source2: seq<'T2>) = - checkNonNull "source1" source1 checkNonNull "source2" source2 - use e1 = source1.GetEnumerator() use e2 = source2.GetEnumerator() - let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f) - let mutable state = state - while e1.MoveNext() && e2.MoveNext() do - state <- f.Invoke(state, e1.Current, e2.Current) - - state + source1 + |> foreach (fun halt -> + { new Composer.Internal.Folder<_,'State> (state) with + override this.ProcessNext value = + if (e2.MoveNext()) then + this.Value <- f.Invoke(this.Value, value, e2.Current) + else + halt() + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun fold -> fold.Value [] let reduce f (source : seq<'T>) = @@ -2526,27 +2545,43 @@ namespace Microsoft.FSharp.Collections [] let forall2 p (source1: seq<_>) (source2: seq<_>) = - checkNonNull "source1" source1 checkNonNull "source2" source2 - use e1 = source1.GetEnumerator() + use e2 = source2.GetEnumerator() let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(p) - let mutable ok = true - while (ok && e1.MoveNext() && e2.MoveNext()) do - ok <- p.Invoke(e1.Current, e2.Current) - ok + + source1 + |> foreach (fun halt -> + { new Composer.Internal.Folder<_,bool> (true) with + override this.ProcessNext value = + if (e2.MoveNext()) then + if not (p.Invoke(value, e2.Current)) then + this.Value <- false + halt() + else + halt() + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun all -> all.Value [] let exists2 p (source1: seq<_>) (source2: seq<_>) = - checkNonNull "source1" source1 checkNonNull "source2" source2 - use e1 = source1.GetEnumerator() + use e2 = source2.GetEnumerator() let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(p) - let mutable ok = false - while (not ok && e1.MoveNext() && e2.MoveNext()) do - ok <- p.Invoke(e1.Current, e2.Current) - ok + + source1 + |> foreach (fun halt -> + { new Composer.Internal.Folder<_,bool> (false) with + override this.ProcessNext value = + if (e2.MoveNext()) then + if p.Invoke(value, e2.Current) then + this.Value <- true + halt() + else + halt() + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun exists -> exists.Value [] let tryHead (source : seq<_>) = From eb58a37f48fb5c4e49674d4be0d0e9fa50a91b02 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sun, 30 Oct 2016 04:56:56 +0100 Subject: [PATCH 27/59] Removed Helpers. qualifier Names are unique and descriptive enough Update NoNeedToTailcall.output.test.bsl for Seq mod Adding types to try to appease test Adding the types doesn't work. Only appearing in portable build, so pondering if it is a compiler bug? Will need to get onto someone about it I think. --- src/fsharp/FSharp.Core/seq.fs | 128 +++++++++--------- ...tailcalls.NoNeedToTailcall.output.test.bsl | 2 +- 2 files changed, 66 insertions(+), 64 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 386a956a87c..b2eb55f0468 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -528,12 +528,14 @@ namespace Microsoft.FSharp.Collections let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) let inline upcastICompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) + open Helpers + type [] SeqComponentFactory<'T,'U> (pipeIdx:``PipeIdx?``) = new() = SeqComponentFactory<'T,'U> (emptyPipeIdx) interface ISeqFactory<'T,'U> with member __.PipeIdx = getPipeIdx pipeIdx - member __.Create _ _ _ = failwith "library implementation error: Create on base factory should not be called" + member __.Create<'V> (_:IOutOfBand) (_:``PipeIdx?``) (_:Consumer<'U,'V>) : Consumer<'T,'V> = failwith "library implementation error: Create on base factory should not be called" and ComposedFactory<'T,'U,'V> private (first:ISeqFactory<'T,'U>, second:ISeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = inherit SeqComponentFactory<'T,'V> (makePipeIdx secondPipeIdx) @@ -543,7 +545,7 @@ namespace Microsoft.FSharp.Collections first.Create outOfBand pipeIdx (second.Create outOfBand (makePipeIdx secondPipeIdx) next) static member Combine (first:ISeqFactory<'T,'U>) (second:ISeqFactory<'U,'V>) : ISeqFactory<'T,'V> = - ComposedFactory(first, second, first.PipeIdx+1) |> Helpers.upcastFactory + ComposedFactory(first, second, first.PipeIdx+1) |> upcastFactory and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () @@ -681,7 +683,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = match choose input with - | Some value -> Helpers.avoidTailCall (next.ProcessNext value) + | Some value -> avoidTailCall (next.ProcessNext value) | None -> false and Distinct<'T,'V when 'T: equality> (next:Consumer<'T,'V>) = @@ -691,7 +693,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if hashSet.Add input then - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else false @@ -702,7 +704,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if hashSet.Add(keyFunction input) then - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else false @@ -713,7 +715,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if cached.Value.Add input then - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else false @@ -724,7 +726,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if filter input then - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else false @@ -733,7 +735,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if filter input then - Helpers.avoidTailCall (next.ProcessNext (map input)) + avoidTailCall (next.ProcessNext (map input)) else false @@ -743,7 +745,7 @@ namespace Microsoft.FSharp.Collections override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) override __.ProcessNext (input:'T) : bool = - Helpers.avoidTailCall (next.ProcessNext (map input)) + avoidTailCall (next.ProcessNext (map input)) and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = inherit SeqComponent<'First,'V>(next) @@ -753,7 +755,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'First) : bool = if input2.MoveNext () then - Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) + avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -769,7 +771,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'Second) : bool = if input1.MoveNext () then - Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) + avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -786,7 +788,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'First) : bool = if input2.MoveNext () && input3.MoveNext () then - Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) + avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -801,7 +803,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = let u = map input if filter u then - Helpers.avoidTailCall (next.ProcessNext u) + avoidTailCall (next.ProcessNext u) else false @@ -813,7 +815,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = idx <- idx + 1 - Helpers.avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) + avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = inherit SeqComponent<'First,'V>(next) @@ -825,7 +827,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'First) : bool = if input2.MoveNext () then idx <- idx + 1 - Helpers.avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) + avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -847,7 +849,7 @@ namespace Microsoft.FSharp.Collections else let currentPair = lastValue, input lastValue <- input - Helpers.avoidTailCall (next.ProcessNext currentPair) + avoidTailCall (next.ProcessNext currentPair) and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:Consumer<'State,'V>) = inherit SeqComponent<'T,'V>(next) @@ -857,7 +859,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = foldResult <- f.Invoke(foldResult, input) - Helpers.avoidTailCall (next.ProcessNext foldResult) + avoidTailCall (next.ProcessNext foldResult) and Skip<'T,'V> (skipCount:int, next:Consumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) @@ -876,7 +878,7 @@ namespace Microsoft.FSharp.Collections count <- count + 1 false else - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) override __.OnComplete _ = if count < skipCount then @@ -895,9 +897,9 @@ namespace Microsoft.FSharp.Collections if skip then false else - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) and Take<'T,'V> (takeCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipelineIdx:int) = inherit Truncate<'T, 'V>(takeCount, outOfBand, next, pipelineIdx) @@ -913,7 +915,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if predicate input then - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else outOfBand.StopFurtherProcessing pipeIdx false @@ -928,7 +930,7 @@ namespace Microsoft.FSharp.Collections first <- false false else - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) override this.OnComplete _ = if first then @@ -946,7 +948,7 @@ namespace Microsoft.FSharp.Collections count <- count + 1 if count = truncateCount then outOfBand.StopFurtherProcessing pipeIdx - next.ProcessNext input + avoidTailCall (next.ProcessNext input) else outOfBand.StopFurtherProcessing pipeIdx false @@ -1034,10 +1036,10 @@ namespace Microsoft.FSharp.Collections let consumer = current.Create pipeline emptyPipeIdx result try executeOn pipeline consumer - (Helpers.upcastICompletionChaining consumer).OnComplete pipeline.HaltedIdx + (upcastICompletionChaining consumer).OnComplete pipeline.HaltedIdx result finally - (Helpers.upcastICompletionChaining consumer).OnDispose () + (upcastICompletionChaining consumer).OnDispose () module Enumerable = type Empty<'T>() = @@ -1062,7 +1064,7 @@ namespace Microsoft.FSharp.Collections seqComponent.OnDispose () interface IEnumerator with - member this.Current : obj = box ((Helpers.upcastEnumerator this)).Current + member this.Current : obj = box ((upcastEnumerator this)).Current member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)" member __.Reset () : unit = noReset () @@ -1081,13 +1083,13 @@ namespace Microsoft.FSharp.Collections abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> - default this.Append source = Helpers.upcastEnumerable (AppendEnumerable [this; source]) + default this.Append source = upcastEnumerable (AppendEnumerable [this; source]) interface IEnumerable with member this.GetEnumerator () : IEnumerator = - let genericEnumerable = Helpers.upcastEnumerable this + let genericEnumerable = upcastEnumerable this let genericEnumerator = genericEnumerable.GetEnumerator () - Helpers.upcastEnumeratorNonGeneric genericEnumerator + upcastEnumeratorNonGeneric genericEnumerator interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement () @@ -1107,7 +1109,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1120,7 +1122,7 @@ namespace Microsoft.FSharp.Collections try source.Dispose () finally - (Helpers.upcastICompletionChaining seqComponent).OnDispose () + (upcastICompletionChaining seqComponent).OnDispose () and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:ISeqFactory<'T,'U>) = inherit EnumerableBase<'U>() @@ -1128,11 +1130,11 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - Helpers.upcastSeq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) + upcastSeq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.enumerable enumerable) @@ -1162,7 +1164,7 @@ namespace Microsoft.FSharp.Collections | _ -> active.Current interface IEnumerator with - member this.Current = box ((Helpers.upcastEnumerator this)).Current + member this.Current = box ((upcastEnumerator this)).Current member __.MoveNext () = state <- SeqProcessNextStates.InProcess moveNext () @@ -1178,14 +1180,14 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = - Helpers.upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) + upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) override this.Append source = - Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) + upcastEnumerable (AppendEnumerable (source :: sources)) interface ISeq<'T> with member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - Helpers.upcastSeq (Enumerable<'T,'V>(this, next)) + upcastSeq (Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) @@ -1195,17 +1197,17 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = - Helpers.upcastEnumerator (new ConcatEnumerator<_,_> (sources)) + upcastEnumerator (new ConcatEnumerator<_,_> (sources)) interface ISeq<'T> with member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - Helpers.upcastSeq (Enumerable<'T,'V>(this, next)) + upcastSeq (Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) let create enumerable current = - Helpers.upcastSeq (Enumerable(enumerable, current)) + upcastSeq (Enumerable(enumerable, current)) module EmptyEnumerable = type Enumerable<'T> () = @@ -1218,11 +1220,11 @@ namespace Microsoft.FSharp.Collections member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>() override this.Append source = - Helpers.upcastEnumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) + upcastEnumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) interface ISeq<'T> with member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - Helpers.upcastSeq (Enumerable.Enumerable<'T,'V>(this, next)) + upcastSeq (Enumerable.Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) @@ -1253,7 +1255,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1267,17 +1269,17 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - Helpers.upcastSeq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) + upcastSeq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.array (delayedArray ())) let createDelayed (delayedArray:unit->array<'T>) (current:ISeqFactory<'T,'U>) = - Helpers.upcastSeq (Enumerable(delayedArray, current)) + upcastSeq (Enumerable(delayedArray, current)) let create (array:array<'T>) (current:ISeqFactory<'T,'U>) = createDelayed (fun () -> array) current @@ -1304,7 +1306,7 @@ namespace Microsoft.FSharp.Collections moveNext tail | _ -> result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1318,17 +1320,17 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - Helpers.upcastSeq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) + upcastSeq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.list alist) let create alist current = - Helpers.upcastSeq (Enumerable(alist, current)) + upcastSeq (Enumerable(alist, current)) module Unfold = type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, result:Result<'U>) = @@ -1357,11 +1359,11 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - Helpers.upcastSeq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + upcastSeq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.unfold generator state) @@ -1419,7 +1421,7 @@ namespace Microsoft.FSharp.Collections raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1433,11 +1435,11 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - Helpers.upcastSeq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + upcastSeq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) member this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = let terminatingIdx = getTerminatingIdx count @@ -1505,10 +1507,10 @@ namespace Microsoft.FSharp.Collections interface ISeq<'T> with member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - Helpers.upcastSeq (Enumerable<'T,'V>(count, f, next)) + upcastSeq (Enumerable<'T,'V>(count, f, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (Helpers.upcastEnumerable this)) + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (upcastEnumerable this)) open RuntimeHelpers @@ -1517,9 +1519,9 @@ namespace Microsoft.FSharp.Collections checkNonNull "source" source match source with | :? ISeq<'T> as s -> s - | :? array<'T> as a -> Helpers.upcastSeq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) - | :? list<'T> as a -> Helpers.upcastSeq (List.Enumerable(a, IdentityFactory.Instance)) - | _ -> Helpers.upcastSeq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) + | :? array<'T> as a -> upcastSeq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) + | :? list<'T> as a -> upcastSeq (List.Enumerable(a, IdentityFactory.Instance)) + | _ -> upcastSeq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) let inline foreach f (source:ISeq<_>) = source.ForEach f @@ -1532,17 +1534,17 @@ namespace Microsoft.FSharp.Collections [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> = - Helpers.upcastSeq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) + upcastSeq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) [] let initInfinite<'T> (f:int->'T) : ISeq<'T> = - Helpers.upcastSeq (new Init.EnumerableDecider<'T>(Nullable (), f)) + upcastSeq (new Init.EnumerableDecider<'T>(Nullable (), f)) [] let init<'T> (count:int) (f:int->'T) : ISeq<'T> = if count < 0 then invalidArgInputMustBeNonNegative "count" count elif count = 0 then empty else - Helpers.upcastSeq (new Init.EnumerableDecider<'T>(Nullable count, f)) + upcastSeq (new Init.EnumerableDecider<'T>(Nullable count, f)) [] let iter f (source:ISeq<'T>) = diff --git a/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl b/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl index 785a337a2f4..5f4e677efc6 100644 --- a/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl +++ b/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl @@ -38,7 +38,7 @@ value simpleLibraryCall6 at line 60 does not make a critical tailcall value simpleLibraryCall7 at line 61 does not make a critical tailcall value simpleLibraryCall8 at line 62 does not make a critical tailcall value simpleLibraryCall9 at line 63 does not make a critical tailcall -value simpleLibraryCall10 at line 65 may make a critical tailcall +value simpleLibraryCall10 at line 65 does not make a critical tailcall value simpleLibraryCall11 at line 66 does not make a critical tailcall value simpleLibraryCall12 at line 67 does not make a critical tailcall value simpleLibraryCall13 at line 68 does not make a critical tailcall From 617c72cdf4afe0f2c0a477a59e4adff1db41042d Mon Sep 17 00:00:00 2001 From: liboz Date: Mon, 31 Oct 2016 19:40:51 -0400 Subject: [PATCH 28/59] seq.windowed --- src/fsharp/FSharp.Core/seq.fs | 53 ++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index b2eb55f0468..6cbf1dc1ca5 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -654,6 +654,11 @@ namespace Microsoft.FSharp.Collections inherit SeqComponentFactory<'T,'T> () interface ISeqFactory<'T,'T> with member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, getPipeIdx pipeIdx) + + and WindowedFactory<'T> (windowSize:int) = + inherit SeqComponentFactory<'T, 'T[]> () + interface ISeqFactory<'T, 'T[]> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T[],'V>) : Consumer<'T,'V> = upcast Windowed (windowSize, next) and [] SeqComponent<'T,'U> (next:ICompletionChaining) = inherit Consumer<'T,'U>() @@ -953,6 +958,34 @@ namespace Microsoft.FSharp.Collections outOfBand.StopFurtherProcessing pipeIdx false + and Windowed<'T,'V> (windowSize: int, next:Consumer<'T[],'V>) = + inherit SeqComponent<'T,'V>(next) + + let arr = Array.zeroCreateUnchecked windowSize + let r = ref (windowSize - 1) + let i = ref 0 + + let arrWindow innerDerefI j = arr.[(innerDerefI+j) % windowSize] + + override __.ProcessNext (input:'T) : bool = + let derefI = !i + arr.[derefI] <- input + i := (derefI + 1) % windowSize + let derefR = !r + if derefR = 0 then + let innerDerefI = !i + if windowSize < 32 then + let window = Array.init windowSize (arrWindow innerDerefI) + avoidTailCall (next.ProcessNext window) + else + let window = Array.zeroCreateUnchecked windowSize + Array.Copy(arr, innerDerefI, window, 0, windowSize - innerDerefI) + Array.Copy(arr, 0, window, windowSize - innerDerefI, innerDerefI) + avoidTailCall (next.ProcessNext window) + else + r := (derefR - 1) + false + type SeqProcessNextStates = | InProcess = 0 | NotStarted = 1 @@ -2150,27 +2183,9 @@ namespace Microsoft.FSharp.Collections // windowed : int -> seq<'T> -> seq<'T[]> [] let windowed windowSize (source: seq<_>) = - checkNonNull "source" source if windowSize <= 0 then invalidArgFmt "windowSize" "{0}\nwindowSize = {1}" [|SR.GetString SR.inputMustBePositive; windowSize|] - seq { - let arr = Array.zeroCreateUnchecked windowSize - let r = ref (windowSize - 1) - let i = ref 0 - use e = source.GetEnumerator() - while e.MoveNext() do - arr.[!i] <- e.Current - i := (!i + 1) % windowSize - if !r = 0 then - if windowSize < 32 then - yield Array.init windowSize (fun j -> arr.[(!i+j) % windowSize]) - else - let result = Array.zeroCreateUnchecked windowSize - Array.Copy(arr, !i, result, 0, windowSize - !i) - Array.Copy(arr, 0, result, windowSize - !i, !i) - yield result - else r := (!r - 1) - } + source |> seqFactory (Composer.WindowedFactory (windowSize)) [] let cache (source : seq<'T>) = From 392f3e739df23c6ed5a076c06ae34f31d0a86b5a Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Tue, 1 Nov 2016 18:25:18 +1100 Subject: [PATCH 29/59] Tightening up Seq.windowed - removed ref vars, as can just us let mutable - renamed variables to more meaningful names - removed modulus because I can --- src/fsharp/FSharp.Core/seq.fs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 6cbf1dc1ca5..6ba2d789ece 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -961,30 +961,30 @@ namespace Microsoft.FSharp.Collections and Windowed<'T,'V> (windowSize: int, next:Consumer<'T[],'V>) = inherit SeqComponent<'T,'V>(next) - let arr = Array.zeroCreateUnchecked windowSize - let r = ref (windowSize - 1) - let i = ref 0 + let circularBuffer = Array.zeroCreateUnchecked windowSize + let mutable idx = 0 - let arrWindow innerDerefI j = arr.[(innerDerefI+j) % windowSize] + let mutable priming = windowSize - 1 override __.ProcessNext (input:'T) : bool = - let derefI = !i - arr.[derefI] <- input - i := (derefI + 1) % windowSize - let derefR = !r - if derefR = 0 then - let innerDerefI = !i + circularBuffer.[idx] <- input + + idx <- idx + 1 + if idx = windowSize then + idx <- 0 + + if priming > 0 then + priming <- priming - 1 + false + else if windowSize < 32 then - let window = Array.init windowSize (arrWindow innerDerefI) + let window = Array.init windowSize (fun i -> circularBuffer.[(idx+i) % windowSize]) avoidTailCall (next.ProcessNext window) else let window = Array.zeroCreateUnchecked windowSize - Array.Copy(arr, innerDerefI, window, 0, windowSize - innerDerefI) - Array.Copy(arr, 0, window, windowSize - innerDerefI, innerDerefI) + Array.Copy(circularBuffer, idx, window, 0, windowSize - idx) + Array.Copy(circularBuffer, 0, window, windowSize - idx, idx) avoidTailCall (next.ProcessNext window) - else - r := (derefR - 1) - false type SeqProcessNextStates = | InProcess = 0 From c5ae38aa5d26bd073a1d5df46abd91628d862057 Mon Sep 17 00:00:00 2001 From: liboz Date: Thu, 3 Nov 2016 22:50:07 -0400 Subject: [PATCH 30/59] Reduce the diff on seq.fs so that it is easier to review on GitHub --- src/fsharp/FSharp.Core/FSharp.Core.fsproj | 12 + src/fsharp/FSharp.Core/seq.fs | 1823 +-------------------- src/fsharp/FSharp.Core/seq.fsi | 167 +- src/fsharp/FSharp.Core/seqcomposer.fs | 1286 +++++++++++++++ src/fsharp/FSharp.Core/seqcomposer.fsi | 757 +++++++++ src/fsharp/FSharp.Core/seqcore.fs | 405 +++++ src/fsharp/FSharp.Core/seqcore.fsi | 150 ++ 7 files changed, 2685 insertions(+), 1915 deletions(-) create mode 100644 src/fsharp/FSharp.Core/seqcomposer.fs create mode 100644 src/fsharp/FSharp.Core/seqcomposer.fsi create mode 100644 src/fsharp/FSharp.Core/seqcore.fs create mode 100644 src/fsharp/FSharp.Core/seqcore.fsi diff --git a/src/fsharp/FSharp.Core/FSharp.Core.fsproj b/src/fsharp/FSharp.Core/FSharp.Core.fsproj index 8ad25ce16c7..b03f6d410c1 100644 --- a/src/fsharp/FSharp.Core/FSharp.Core.fsproj +++ b/src/fsharp/FSharp.Core/FSharp.Core.fsproj @@ -94,6 +94,18 @@ Collections/collections.fs + + + Collections/seqcore.fsi + + + Collections/seqcore.fs + + + Collections/seqcomposer.fsi + + + Collections/seqcomposer.fs Collections/seq.fsi diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 6ba2d789ece..8d9686b9431 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -1,410 +1,5 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.FSharp.Collections - #nowarn "52" // The value has been copied to ensure the original is not mutated by this operation - - open System - open System.Diagnostics - open System.Collections - open System.Collections.Generic - open Microsoft.FSharp.Core - open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators - open Microsoft.FSharp.Core.Operators - open Microsoft.FSharp.Control - open Microsoft.FSharp.Collections - - module IEnumerator = - - let noReset() = raise (new System.NotSupportedException(SR.GetString(SR.resetNotSupported))) - let notStarted() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationNotStarted))) - let alreadyFinished() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationAlreadyFinished))) - let check started = if not started then notStarted() - let dispose (r : System.IDisposable) = r.Dispose() - - let cast (e : IEnumerator) : IEnumerator<'T> = - { new IEnumerator<'T> with - member x.Current = unbox<'T> e.Current - interface IEnumerator with - member x.Current = unbox<'T> e.Current :> obj - member x.MoveNext() = e.MoveNext() - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = - match e with - | :? System.IDisposable as e -> e.Dispose() - | _ -> () } - - /// A concrete implementation of an enumerator that returns no values - [] - type EmptyEnumerator<'T>() = - let mutable started = false - interface IEnumerator<'T> with - member x.Current = - check started - (alreadyFinished() : 'T) - - interface System.Collections.IEnumerator with - member x.Current = - check started - (alreadyFinished() : obj) - member x.MoveNext() = - if not started then started <- true - false - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = () - - let Empty<'T> () = (new EmptyEnumerator<'T>() :> IEnumerator<'T>) - - let readAndClear r = - lock r (fun () -> match !r with None -> None | Some _ as res -> r := None; res) - - let generateWhileSome openf compute closef : IEnumerator<'U> = - let started = ref false - let curr = ref None - let state = ref (Some(openf())) - let getCurr() = - check !started - match !curr with None -> alreadyFinished() | Some x -> x - let start() = if not !started then (started := true) - - let dispose() = readAndClear state |> Option.iter closef - let finish() = (try dispose() finally curr := None) - { new IEnumerator<'U> with - member x.Current = getCurr() - interface IEnumerator with - member x.Current = box (getCurr()) - member x.MoveNext() = - start() - match !state with - | None -> false (* we started, then reached the end, then got another MoveNext *) - | Some s -> - match (try compute s with e -> finish(); reraise()) with - | None -> finish(); false - | Some _ as x -> curr := x; true - - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = dispose() } - - [] - type Singleton<'T>(v:'T) = - let mutable started = false - interface IEnumerator<'T> with - member x.Current = v - interface IEnumerator with - member x.Current = box v - member x.MoveNext() = if started then false else (started <- true; true) - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = () - - let Singleton x = (new Singleton<'T>(x) :> IEnumerator<'T>) - - let EnumerateThenFinally f (e : IEnumerator<'T>) = - { new IEnumerator<'T> with - member x.Current = e.Current - interface IEnumerator with - member x.Current = (e :> IEnumerator).Current - member x.MoveNext() = e.MoveNext() - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = - try - e.Dispose() - finally - f() - } - - -namespace Microsoft.FSharp.Core.CompilerServices - - open System - open System.Diagnostics - open Microsoft.FSharp.Core - open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators - open Microsoft.FSharp.Core.Operators - open Microsoft.FSharp.Control - open Microsoft.FSharp.Collections - open Microsoft.FSharp.Primitives.Basics - open System.Collections - open System.Collections.Generic - - module RuntimeHelpers = - - [] - type internal StructBox<'T when 'T:equality>(value:'T) = - member x.Value = value - static member Comparer = - let gcomparer = HashIdentity.Structural<'T> - { new IEqualityComparer> with - member __.GetHashCode(v) = gcomparer.GetHashCode(v.Value) - member __.Equals(v1,v2) = gcomparer.Equals(v1.Value,v2.Value) } - - let inline checkNonNull argName arg = - match box arg with - | null -> nullArg argName - | _ -> () - - let mkSeq f = - { new IEnumerable<'U> with - member x.GetEnumerator() = f() - interface IEnumerable with - member x.GetEnumerator() = (f() :> IEnumerator) } - - [] - type EmptyEnumerable<'T> = - | EmptyEnumerable - interface IEnumerable<'T> with - member x.GetEnumerator() = IEnumerator.Empty<'T>() - interface IEnumerable with - member x.GetEnumerator() = (IEnumerator.Empty<'T>() :> IEnumerator) - - let Generate openf compute closef = - mkSeq (fun () -> IEnumerator.generateWhileSome openf compute closef) - - let GenerateUsing (openf : unit -> ('U :> System.IDisposable)) compute = - Generate openf compute (fun (s:'U) -> s.Dispose()) - - let EnumerateFromFunctions opener moveNext current = - Generate - opener - (fun x -> if moveNext x then Some(current x) else None) - (fun x -> match box(x) with :? System.IDisposable as id -> id.Dispose() | _ -> ()) - - // A family of enumerators that can have additional 'finally' actions added to the enumerator through - // the use of mutation. This is used to 'push' the disposal action for a 'use' into the next enumerator. - // For example, - // seq { use x = ... - // while ... } - // results in the 'while' loop giving an adjustable enumerator. This is then adjusted by adding the disposal action - // from the 'use' into the enumerator. This means that we avoid constructing a two-deep enumerator chain in this - // common case. - type IFinallyEnumerator = - abstract AppendFinallyAction : (unit -> unit) -> unit - - /// A concrete implementation of IEnumerable that adds the given compensation to the "Dispose" chain of any - /// enumerators returned by the enumerable. - [] - type FinallyEnumerable<'T>(compensation: unit -> unit, restf: unit -> seq<'T>) = - interface IEnumerable<'T> with - member x.GetEnumerator() = - try - let ie = restf().GetEnumerator() - match ie with - | :? IFinallyEnumerator as a -> - a.AppendFinallyAction(compensation) - ie - | _ -> - IEnumerator.EnumerateThenFinally compensation ie - with e -> - compensation() - reraise() - interface IEnumerable with - member x.GetEnumerator() = ((x :> IEnumerable<'T>).GetEnumerator() :> IEnumerator) - - /// An optimized object for concatenating a sequence of enumerables - [] - type ConcatEnumerator<'T,'U when 'U :> seq<'T>>(sources: seq<'U>) = - let mutable outerEnum = sources.GetEnumerator() - let mutable currInnerEnum = IEnumerator.Empty() - - let mutable started = false - let mutable finished = false - let mutable compensations = [] - - [] // false = unchecked - val mutable private currElement : 'T - - member x.Finish() = - finished <- true - try - match currInnerEnum with - | null -> () - | _ -> - try - currInnerEnum.Dispose() - finally - currInnerEnum <- null - finally - try - match outerEnum with - | null -> () - | _ -> - try - outerEnum.Dispose() - finally - outerEnum <- null - finally - let rec iter comps = - match comps with - | [] -> () - | h::t -> - try h() finally iter t - try - compensations |> List.rev |> iter - finally - compensations <- [] - - member x.GetCurrent() = - IEnumerator.check started - if finished then IEnumerator.alreadyFinished() else x.currElement - - interface IFinallyEnumerator with - member x.AppendFinallyAction(f) = - compensations <- f :: compensations - - interface IEnumerator<'T> with - member x.Current = x.GetCurrent() - - interface IEnumerator with - member x.Current = box (x.GetCurrent()) - - member x.MoveNext() = - if not started then (started <- true) - if finished then false - else - let rec takeInner () = - // check the inner list - if currInnerEnum.MoveNext() then - x.currElement <- currInnerEnum.Current - true - else - // check the outer list - let rec takeOuter() = - if outerEnum.MoveNext() then - let ie = outerEnum.Current - // Optimization to detect the statically-allocated empty IEnumerables - match box ie with - | :? EmptyEnumerable<'T> -> - // This one is empty, just skip, don't call GetEnumerator, try again - takeOuter() - | _ -> - // OK, this one may not be empty. - // Don't forget to dispose of the enumerator for the inner list now we're done with it - currInnerEnum.Dispose() - currInnerEnum <- ie.GetEnumerator() - takeInner () - else - // We're done - x.Finish() - false - takeOuter() - takeInner () - - member x.Reset() = IEnumerator.noReset() - - interface System.IDisposable with - member x.Dispose() = - if not finished then - x.Finish() - - let EnumerateUsing (resource : 'T :> System.IDisposable) (rest: 'T -> #seq<'U>) = - (FinallyEnumerable((fun () -> match box resource with null -> () | _ -> resource.Dispose()), - (fun () -> rest resource :> seq<_>)) :> seq<_>) - - let mkConcatSeq (sources: seq<'U :> seq<'T>>) = - mkSeq (fun () -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>) - - let EnumerateWhile (g : unit -> bool) (b: seq<'T>) : seq<'T> = - let started = ref false - let curr = ref None - let getCurr() = - IEnumerator.check !started - match !curr with None -> IEnumerator.alreadyFinished() | Some x -> x - let start() = if not !started then (started := true) - - let finish() = (curr := None) - mkConcatSeq - (mkSeq (fun () -> - { new IEnumerator<_> with - member x.Current = getCurr() - interface IEnumerator with - member x.Current = box (getCurr()) - member x.MoveNext() = - start() - let keepGoing = (try g() with e -> finish (); reraise ()) in - if keepGoing then - curr := Some(b); true - else - finish(); false - member x.Reset() = IEnumerator.noReset() - interface System.IDisposable with - member x.Dispose() = () })) - - let EnumerateThenFinally (rest : seq<'T>) (compensation : unit -> unit) = - (FinallyEnumerable(compensation, (fun () -> rest)) :> seq<_>) - - let CreateEvent (add : 'Delegate -> unit) (remove : 'Delegate -> unit) (create : (obj -> 'Args -> unit) -> 'Delegate ) :IEvent<'Delegate,'Args> = - // Note, we implement each interface explicitly: this works around a bug in the CLR - // implementation on CompactFramework 3.7, used on Windows Phone 7 - { new obj() with - member x.ToString() = "" - interface IEvent<'Delegate,'Args> - interface IDelegateEvent<'Delegate> with - member x.AddHandler(h) = add h - member x.RemoveHandler(h) = remove h - interface System.IObservable<'Args> with - member x.Subscribe(r:IObserver<'Args>) = - let h = create (fun _ args -> r.OnNext(args)) - add h - { new System.IDisposable with - member x.Dispose() = remove h } } - - - [] - type GeneratedSequenceBase<'T>() = - let mutable redirectTo : GeneratedSequenceBase<'T> = Unchecked.defaultof<_> - let mutable redirect : bool = false - - abstract GetFreshEnumerator : unit -> IEnumerator<'T> - abstract GenerateNext : next:byref> -> int // 0 = Stop, 1 = Yield, 2 = Goto - abstract Close: unit -> unit - abstract CheckClose: bool - abstract LastGenerated : 'T - - //[] - member x.MoveNextImpl() = - let active = - if redirect then redirectTo - else x - let mutable target = null - match active.GenerateNext(&target) with - | 1 -> - true - | 2 -> - match target.GetEnumerator() with - | :? GeneratedSequenceBase<'T> as g when not active.CheckClose -> - redirectTo <- g - | e -> - redirectTo <- - { new GeneratedSequenceBase<'T>() with - member x.GetFreshEnumerator() = e - member x.GenerateNext(_) = if e.MoveNext() then 1 else 0 - member x.Close() = try e.Dispose() finally active.Close() - member x.CheckClose = true - member x.LastGenerated = e.Current } - redirect <- true - x.MoveNextImpl() - | _ (* 0 *) -> - false - - interface IEnumerable<'T> with - member x.GetEnumerator() = x.GetFreshEnumerator() - interface IEnumerable with - member x.GetEnumerator() = (x.GetFreshEnumerator() :> IEnumerator) - interface IEnumerator<'T> with - member x.Current = if redirect then redirectTo.LastGenerated else x.LastGenerated - member x.Dispose() = if redirect then redirectTo.Close() else x.Close() - interface IEnumerator with - member x.Current = box (if redirect then redirectTo.LastGenerated else x.LastGenerated) - - //[] - member x.MoveNext() = x.MoveNextImpl() - - member x.Reset() = raise <| new System.NotSupportedException() - - namespace Microsoft.FSharp.Collections open System @@ -419,6 +14,7 @@ namespace Microsoft.FSharp.Collections open Microsoft.FSharp.Control open Microsoft.FSharp.Collections open Microsoft.FSharp.Primitives.Basics + open Microsoft.FSharp.Collections.IEnumerator [] type CachedSeq<'T>(cleanup,res:seq<'T>) = @@ -434,1300 +30,27 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = - module Composer = - open IEnumerator - - module Internal = - type PipeIdx = int - type ``PipeIdx?`` = Nullable - let emptyPipeIdx = Nullable () - let inline getPipeIdx (maybePipeIdx:``PipeIdx?``) = if maybePipeIdx.HasValue then maybePipeIdx.Value else 1 - let inline makePipeIdx (pipeIdx:PipeIdx) = Nullable pipeIdx - - type ICompletionChaining = - abstract OnComplete : PipeIdx -> unit - abstract OnDispose : unit -> unit - - type IOutOfBand = - abstract StopFurtherProcessing : PipeIdx -> unit - - [] - type Consumer<'T,'U> () = - abstract ProcessNext : input:'T -> bool - - abstract OnComplete : PipeIdx -> unit - abstract OnDispose : unit -> unit - - default __.OnComplete _ = () - default __.OnDispose () = () - - interface ICompletionChaining with - member this.OnComplete terminatingIdx = - this.OnComplete terminatingIdx - - member this.OnDispose () = - try this.OnDispose () - finally () - - [] - type Values<'a,'b> = - val mutable _1 : 'a - val mutable _2 : 'b - - new (a:'a, b: 'b) = { - _1 = a - _2 = b - } - - [] - type Values<'a,'b,'c> = - val mutable _1 : 'a - val mutable _2 : 'b - val mutable _3 : 'c - - new (a:'a, b:'b, c:'c) = { - _1 = a - _2 = b - _3 = c - } - - [] - type Folder<'T, 'U> = - inherit Consumer<'T,'T> - - val mutable Value : 'U - - new (init) = { - inherit Consumer<'T,'T>() - Value = init - } - - type ISeqFactory<'T,'U> = - abstract PipeIdx : PipeIdx - abstract Create<'V> : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> - - type ISeq<'T> = - inherit IEnumerable<'T> - abstract member Compose<'U> : (ISeqFactory<'T,'U>) -> ISeq<'U> - abstract member ForEach<'consumer when 'consumer :> Consumer<'T,'T>> : f:((unit->unit)->'consumer) -> 'consumer - - open Internal - - module Helpers = - // used for performance reasons; these are not recursive calls, so should be safe - // ** it should be noted that potential changes to the f# compiler may render this function - // ineffictive ** - let inline avoidTailCall boolean = match boolean with true -> true | false -> false - - // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality - // is fixed with the compiler then these functions can be removed. - let inline upcastSeq (t:#ISeq<'T>) : ISeq<'T> = (# "" t : ISeq<'T> #) - let inline upcastFactory (t:#ISeqFactory<'T,'U>) : ISeqFactory<'T,'U> = (# "" t : ISeqFactory<'T,'U> #) - let inline upcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) - let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) - let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) - let inline upcastICompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) - - open Helpers - - type [] SeqComponentFactory<'T,'U> (pipeIdx:``PipeIdx?``) = - new() = SeqComponentFactory<'T,'U> (emptyPipeIdx) - - interface ISeqFactory<'T,'U> with - member __.PipeIdx = getPipeIdx pipeIdx - member __.Create<'V> (_:IOutOfBand) (_:``PipeIdx?``) (_:Consumer<'U,'V>) : Consumer<'T,'V> = failwith "library implementation error: Create on base factory should not be called" - - and ComposedFactory<'T,'U,'V> private (first:ISeqFactory<'T,'U>, second:ISeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = - inherit SeqComponentFactory<'T,'V> (makePipeIdx secondPipeIdx) - - interface ISeqFactory<'T,'V> with - member this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'V,'W>) : Consumer<'T,'W> = - first.Create outOfBand pipeIdx (second.Create outOfBand (makePipeIdx secondPipeIdx) next) - - static member Combine (first:ISeqFactory<'T,'U>) (second:ISeqFactory<'U,'V>) : ISeqFactory<'T,'V> = - ComposedFactory(first, second, first.PipeIdx+1) |> upcastFactory - - and ChooseFactory<'T,'U> (filter:'T->option<'U>) = - inherit SeqComponentFactory<'T,'U> () - interface ISeqFactory<'T,'U> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) - - and DistinctFactory<'T when 'T: equality> () = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) - - and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) - - and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) - - and FilterFactory<'T> (filter:'T->bool) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = - match next with - | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter - | _ -> upcast Filter (filter, next) - - and IdentityFactory<'T> () = - inherit SeqComponentFactory<'T,'T> () - static let singleton = IdentityFactory<'T>() - interface ISeqFactory<'T,'T> with - member __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next - static member Instance = singleton - - and MapFactory<'T,'U> (map:'T->'U) = - inherit SeqComponentFactory<'T,'U> () - interface ISeqFactory<'T,'U> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = - match next with - | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map - | _ -> upcast Map<_,_,_> (map, next) - - and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = - inherit SeqComponentFactory<'First,'U> () - interface ISeqFactory<'First,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, outOfBand, next, getPipeIdx pipeIdx) - - and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = - inherit SeqComponentFactory<'Second,'U> () - interface ISeqFactory<'Second,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, outOfBand, next, getPipeIdx pipeIdx) - - and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = - inherit SeqComponentFactory<'First,'U> () - interface ISeqFactory<'First,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, outOfBand, next, getPipeIdx pipeIdx) - - and MapiFactory<'T,'U> (mapi:int->'T->'U) = - inherit SeqComponentFactory<'T,'U> () - interface ISeqFactory<'T,'U> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Mapi (mapi, next) - - and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = - inherit SeqComponentFactory<'First,'U> () - interface ISeqFactory<'First,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, outOfBand, next, getPipeIdx pipeIdx) - - and PairwiseFactory<'T> () = - inherit SeqComponentFactory<'T,'T*'T> () - interface ISeqFactory<'T,'T*'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) - - and ScanFactory<'T,'State> (folder:'State->'T->'State, initialState:'State) = - inherit SeqComponentFactory<'T,'State> () - interface ISeqFactory<'T,'State> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) - - and SkipFactory<'T> (count:int) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, next) - - and SkipWhileFactory<'T> (predicate:'T->bool) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) - - and TakeWhileFactory<'T> (predicate:'T->bool) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, outOfBand, next, getPipeIdx pipeIdx) - - and TakeFactory<'T> (count:int) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, outOfBand, next, getPipeIdx pipeIdx) - - and TailFactory<'T> () = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) - - and TruncateFactory<'T> (count:int) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, getPipeIdx pipeIdx) - - and WindowedFactory<'T> (windowSize:int) = - inherit SeqComponentFactory<'T, 'T[]> () - interface ISeqFactory<'T, 'T[]> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T[],'V>) : Consumer<'T,'V> = upcast Windowed (windowSize, next) - - and [] SeqComponent<'T,'U> (next:ICompletionChaining) = - inherit Consumer<'T,'U>() - - // Seq.init(Infinite)? lazily uses Current. The only Composer component that can do that is Skip - // and it can only do it at the start of a sequence - abstract Skipping : unit -> bool - - abstract CreateMap<'S> : map:('S->'T) -> SeqComponent<'S,'U> - abstract CreateFilter : filter:('T->bool) -> SeqComponent<'T,'U> - - interface ICompletionChaining with - member this.OnComplete terminatingIdx = - this.OnComplete terminatingIdx - next.OnComplete terminatingIdx - member this.OnDispose () = - try this.OnDispose () - finally next.OnDispose () - - default __.Skipping () = false - - default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) - default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) - - and Choose<'T,'U,'V> (choose:'T->option<'U>, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - match choose input with - | Some value -> avoidTailCall (next.ProcessNext value) - | None -> false - - and Distinct<'T,'V when 'T: equality> (next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) - - override __.ProcessNext (input:'T) : bool = - if hashSet.Add input then - avoidTailCall (next.ProcessNext input) - else - false - - and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) - - override __.ProcessNext (input:'T) : bool = - if hashSet.Add(keyFunction input) then - avoidTailCall (next.ProcessNext input) - else - false - - and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) - - override __.ProcessNext (input:'T) : bool = - if cached.Value.Add input then - avoidTailCall (next.ProcessNext input) - else - false - - and Filter<'T,'V> (filter:'T->bool, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) - - override __.ProcessNext (input:'T) : bool = - if filter input then - avoidTailCall (next.ProcessNext input) - else - false - - and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - if filter input then - avoidTailCall (next.ProcessNext (map input)) - else - false - - and Map<'T,'U,'V> (map:'T->'U, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) - - override __.ProcessNext (input:'T) : bool = - avoidTailCall (next.ProcessNext (map input)) - - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(next) - - let input2 = enumerable2.GetEnumerator () - let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map - - override __.ProcessNext (input:'First) : bool = - if input2.MoveNext () then - avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - override __.OnDispose () = - input2.Dispose () - - and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'Second,'V>(next) - - let input1 = enumerable1.GetEnumerator () - let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map - - override __.ProcessNext (input:'Second) : bool = - if input1.MoveNext () then - avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - override __.OnDispose () = - input1.Dispose () - - and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(next) - - let input2 = enumerable2.GetEnumerator () - let input3 = enumerable3.GetEnumerator () - let map' = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt map - - override __.ProcessNext (input:'First) : bool = - if input2.MoveNext () && input3.MoveNext () then - avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - override __.OnDispose () = - try input2.Dispose () - finally input3.Dispose () - - and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - let u = map input - if filter u then - avoidTailCall (next.ProcessNext u) - else - false - - and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable idx = 0 - let mapi' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt mapi - - override __.ProcessNext (input:'T) : bool = - idx <- idx + 1 - avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) - - and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(next) - - let mutable idx = 0 - let input2 = enumerable2.GetEnumerator () - let mapi2' = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt map - - override __.ProcessNext (input:'First) : bool = - if input2.MoveNext () then - idx <- idx + 1 - avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - override __.OnDispose () = - input2.Dispose () - - and Pairwise<'T,'V> (next:Consumer<'T*'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable isFirst = true - let mutable lastValue = Unchecked.defaultof<'T> - - override __.ProcessNext (input:'T) : bool = - if isFirst then - lastValue <- input - isFirst <- false - false - else - let currentPair = lastValue, input - lastValue <- input - avoidTailCall (next.ProcessNext currentPair) - - and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:Consumer<'State,'V>) = - inherit SeqComponent<'T,'V>(next) - - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - let mutable foldResult = initialState - - override __.ProcessNext (input:'T) : bool = - foldResult <- f.Invoke(foldResult, input) - avoidTailCall (next.ProcessNext foldResult) - - and Skip<'T,'V> (skipCount:int, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable count = 0 - - override __.Skipping () = - if count < skipCount then - count <- count + 1 - true - else - false - - override __.ProcessNext (input:'T) : bool = - if count < skipCount then - count <- count + 1 - false - else - avoidTailCall (next.ProcessNext input) - - override __.OnComplete _ = - if count < skipCount then - let x = skipCount - count - invalidOpFmt "tried to skip {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - - and SkipWhile<'T,'V> (predicate:'T->bool, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable skip = true - - override __.ProcessNext (input:'T) : bool = - if skip then - skip <- predicate input - if skip then - false - else - avoidTailCall (next.ProcessNext input) - else - avoidTailCall (next.ProcessNext input) - - and Take<'T,'V> (takeCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipelineIdx:int) = - inherit Truncate<'T, 'V>(takeCount, outOfBand, next, pipelineIdx) - - override this.OnComplete terminatingIdx = - if terminatingIdx < pipelineIdx && this.Count < takeCount then - let x = takeCount - this.Count - invalidOpFmt "tried to take {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - - and TakeWhile<'T,'V> (predicate:'T->bool, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - if predicate input then - avoidTailCall (next.ProcessNext input) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - and Tail<'T, 'V> (next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable first = true - - override __.ProcessNext (input:'T) : bool = - if first then - first <- false - false - else - avoidTailCall (next.ProcessNext input) - - override this.OnComplete _ = - if first then - invalidArg "source" (SR.GetString(SR.notEnoughElements)) - - and Truncate<'T,'V> (truncateCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = - inherit SeqComponent<'T,'V>(next) - - let mutable count = 0 - - member __.Count = count - - override __.ProcessNext (input:'T) : bool = - if count < truncateCount then - count <- count + 1 - if count = truncateCount then - outOfBand.StopFurtherProcessing pipeIdx - avoidTailCall (next.ProcessNext input) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - and Windowed<'T,'V> (windowSize: int, next:Consumer<'T[],'V>) = - inherit SeqComponent<'T,'V>(next) - - let circularBuffer = Array.zeroCreateUnchecked windowSize - let mutable idx = 0 - - let mutable priming = windowSize - 1 - - override __.ProcessNext (input:'T) : bool = - circularBuffer.[idx] <- input - - idx <- idx + 1 - if idx = windowSize then - idx <- 0 - - if priming > 0 then - priming <- priming - 1 - false - else - if windowSize < 32 then - let window = Array.init windowSize (fun i -> circularBuffer.[(idx+i) % windowSize]) - avoidTailCall (next.ProcessNext window) - else - let window = Array.zeroCreateUnchecked windowSize - Array.Copy(circularBuffer, idx, window, 0, windowSize - idx) - Array.Copy(circularBuffer, 0, window, windowSize - idx, idx) - avoidTailCall (next.ProcessNext window) - - type SeqProcessNextStates = - | InProcess = 0 - | NotStarted = 1 - | Finished = 2 - - type Result<'T>() = - let mutable haltedIdx = 0 - - member val Current = Unchecked.defaultof<'T> with get, set - member val SeqState = SeqProcessNextStates.NotStarted with get, set - member __.HaltedIdx = haltedIdx - - interface IOutOfBand with - member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx - - // SetResult<> is used at the end of the chain of SeqComponents to assign the final value - type SetResult<'T> (result:Result<'T>) = - inherit Consumer<'T,'T>() - - override __.ProcessNext (input:'T) : bool = - result.Current <- input - true - - type OutOfBand() = - let mutable haltedIdx = 0 - interface IOutOfBand with member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx - member __.HaltedIdx = haltedIdx - - module ForEach = - let enumerable (enumerable:IEnumerable<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - use enumerator = enumerable.GetEnumerator () - while (outOfBand.HaltedIdx = 0) && (enumerator.MoveNext ()) do - consumer.ProcessNext enumerator.Current |> ignore - - let array (array:array<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let mutable idx = 0 - while (outOfBand.HaltedIdx = 0) && (idx < array.Length) do - consumer.ProcessNext array.[idx] |> ignore - idx <- idx + 1 - - let list (alist:list<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let rec iterate lst = - match outOfBand.HaltedIdx, lst with - | 0, hd :: tl -> - consumer.ProcessNext hd |> ignore - iterate tl - | _ -> () - iterate alist - - let unfold (generator:'S->option<'T*'S>) state (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let rec iterate current = - match outOfBand.HaltedIdx, generator current with - | 0, Some (item, next) -> - consumer.ProcessNext item |> ignore - iterate next - | _ -> () - - iterate state - - let makeIsSkipping (consumer:Consumer<'T,'U>) = - match consumer with - | :? SeqComponent<'T,'U> as c -> c.Skipping - | _ -> fun () -> false - - let init f (terminatingIdx:int) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let mutable idx = -1 - let isSkipping = makeIsSkipping consumer - let mutable maybeSkipping = true - while (outOfBand.HaltedIdx = 0) && (idx < terminatingIdx) do - if maybeSkipping then - maybeSkipping <- isSkipping () - - if (not maybeSkipping) then - consumer.ProcessNext (f (idx+1)) |> ignore - - idx <- idx + 1 - - let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:ISeqFactory<'T,'U>) executeOn = - let pipeline = OutOfBand() - let result = f (fun () -> (pipeline:>IOutOfBand).StopFurtherProcessing (current.PipeIdx+1)) - let consumer = current.Create pipeline emptyPipeIdx result - try - executeOn pipeline consumer - (upcastICompletionChaining consumer).OnComplete pipeline.HaltedIdx - result - finally - (upcastICompletionChaining consumer).OnDispose () - - module Enumerable = - type Empty<'T>() = - let current () = failwith "library implementation error: Current should never be called" - interface IEnumerator<'T> with - member __.Current = current () - interface IEnumerator with - member __.Current = current () - member __.MoveNext () = false - member __.Reset (): unit = noReset () - interface IDisposable with - member __.Dispose () = () - - type EmptyEnumerators<'T>() = - static let element : IEnumerator<'T> = upcast (new Empty<'T> ()) - static member Element = element - - [] - type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ICompletionChaining) = - interface IDisposable with - member __.Dispose() : unit = - seqComponent.OnDispose () - - interface IEnumerator with - member this.Current : obj = box ((upcastEnumerator this)).Current - member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)" - member __.Reset () : unit = noReset () - - interface IEnumerator<'T> with - member __.Current = - if result.SeqState = SeqProcessNextStates.InProcess then result.Current - else - match result.SeqState with - | SeqProcessNextStates.NotStarted -> notStarted() - | SeqProcessNextStates.Finished -> alreadyFinished() - | _ -> failwith "library implementation error: all states should have been handled" - - and [] EnumerableBase<'T> () = - let derivedClassShouldImplement () = - failwith "library implementation error: derived class should implement (should be abstract)" - - abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> - - default this.Append source = upcastEnumerable (AppendEnumerable [this; source]) - - interface IEnumerable with - member this.GetEnumerator () : IEnumerator = - let genericEnumerable = upcastEnumerable this - let genericEnumerator = genericEnumerable.GetEnumerator () - upcastEnumeratorNonGeneric genericEnumerator - - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement () - - interface ISeq<'T> with - member __.Compose _ = derivedClassShouldImplement () - member __.ForEach _ = derivedClassShouldImplement () - - and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit EnumeratorBase<'U>(result, seqComponent) - - let rec moveNext () = - if (result.HaltedIdx = 0) && source.MoveNext () then - if seqComponent.ProcessNext source.Current then - true - else - moveNext () - else - result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx - false - - interface IEnumerator with - member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess - moveNext () - - interface IDisposable with - member __.Dispose() = - try - source.Dispose () - finally - (upcastICompletionChaining seqComponent).OnDispose () - - and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:ISeqFactory<'T,'U>) = - inherit EnumerableBase<'U>() - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) - - interface ISeq<'U> with - member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.enumerable enumerable) - - and ConcatEnumerator<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = - let mutable state = SeqProcessNextStates.NotStarted - let main = sources.GetEnumerator () - - let mutable active = EmptyEnumerators.Element - - let rec moveNext () = - if active.MoveNext () then - true - elif main.MoveNext () then - active.Dispose () - active <- main.Current.GetEnumerator () - moveNext () - else - state <- SeqProcessNextStates.Finished - false - - interface IEnumerator<'T> with - member __.Current = - match state with - | SeqProcessNextStates.NotStarted -> notStarted() - | SeqProcessNextStates.Finished -> alreadyFinished() - | _ -> active.Current - - interface IEnumerator with - member this.Current = box ((upcastEnumerator this)).Current - member __.MoveNext () = - state <- SeqProcessNextStates.InProcess - moveNext () - member __.Reset () = noReset () - - interface IDisposable with - member __.Dispose() = - main.Dispose () - active.Dispose () - - and AppendEnumerable<'T> (sources:list>) = - inherit EnumerableBase<'T>() - - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = - upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) - - override this.Append source = - upcastEnumerable (AppendEnumerable (source :: sources)) - - interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable<'T,'V>(this, next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) - - and ConcatEnumerable<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = - inherit EnumerableBase<'T>() - - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = - upcastEnumerator (new ConcatEnumerator<_,_> (sources)) - - interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable<'T,'V>(this, next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) - - let create enumerable current = - upcastSeq (Enumerable(enumerable, current)) - - module EmptyEnumerable = - type Enumerable<'T> () = - inherit Enumerable.EnumerableBase<'T>() - - static let singleton = Enumerable<'T>() :> ISeq<'T> - static member Instance = singleton - - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>() - - override this.Append source = - upcastEnumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) - - interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable.Enumerable<'T,'V>(this, next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) - - - - module Array = - type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) - - let mutable idx = 0 - let mutable array = Unchecked.defaultof<_> - - let mutable initMoveNext = Unchecked.defaultof<_> - do - initMoveNext <- - fun () -> - result.SeqState <- SeqProcessNextStates.InProcess - array <- delayedArray () - initMoveNext <- ignore - - let rec moveNext () = - if (result.HaltedIdx = 0) && idx < array.Length then - idx <- idx+1 - if seqComponent.ProcessNext array.[idx-1] then - true - else - moveNext () - else - result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx - false - - interface IEnumerator with - member __.MoveNext () = - initMoveNext () - moveNext () - - type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:ISeqFactory<'T,'U>) = - inherit Enumerable.EnumerableBase<'U>() - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - - interface ISeq<'U> with - member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.array (delayedArray ())) - - let createDelayed (delayedArray:unit->array<'T>) (current:ISeqFactory<'T,'U>) = - upcastSeq (Enumerable(delayedArray, current)) - - let create (array:array<'T>) (current:ISeqFactory<'T,'U>) = - createDelayed (fun () -> array) current - - let createDelayedId (delayedArray:unit -> array<'T>) = - createDelayed delayedArray IdentityFactory.Instance - - let createId (array:array<'T>) = - create array IdentityFactory.Instance - - module List = - type Enumerator<'T,'U>(alist:list<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) - - let mutable list = alist - - let rec moveNext current = - match result.HaltedIdx, current with - | 0, head::tail -> - if seqComponent.ProcessNext head then - list <- tail - true - else - moveNext tail - | _ -> - result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx - false - - interface IEnumerator with - member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess - moveNext list - - type Enumerable<'T,'U>(alist:list<'T>, current:ISeqFactory<'T,'U>) = - inherit Enumerable.EnumerableBase<'U>() - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - - interface ISeq<'U> with - member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.list alist) - - let create alist current = - upcastSeq (Enumerable(alist, current)) - - module Unfold = - type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) - - let mutable current = state - - let rec moveNext () = - match result.HaltedIdx, generator current with - | 0, Some (item, nextState) -> - current <- nextState - if seqComponent.ProcessNext item then - true - else - moveNext () - | _ -> false - - interface IEnumerator with - member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess - moveNext () - - type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:ISeqFactory<'T,'U>) = - inherit Enumerable.EnumerableBase<'U>() - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - - interface ISeq<'U> with - member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.unfold generator state) - - module Init = - // The original implementation of "init" delayed the calculation of Current, and so it was possible - // to do MoveNext without it's value being calculated. - // I can imagine only two scenerios where that is possibly sane, although a simple solution is readily - // at hand in both cases. The first is that of an expensive generator function, where you skip the - // first n elements. The simple solution would have just been to have a map ((+) n) as the first operation - // instead. The second case would be counting elements, but that is only of use if you're not filtering - // or mapping or doing anything else (as that would cause Current to be evaluated!) and - // so you already know what the count is!! Anyway, someone thought it was a good idea, so - // I have had to add an extra function that is used in Skip to determine if we are touching - // Current or not. - type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:SeqComponent<'T,'U>, signal:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) - - let getTerminatingIdx (count:Nullable) = - // we are offset by 1 to allow for values going up to System.Int32.MaxValue - // System.Int32.MaxValue is an illegal value for the "infinite" sequence - if count.HasValue then - count.Value - 1 - else - System.Int32.MaxValue - - type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) - - let isSkipping = - ForEach.makeIsSkipping seqComponent - - let terminatingIdx = - getTerminatingIdx count - - let mutable maybeSkipping = true - let mutable idx = -1 - - let rec moveNext () = - if (result.HaltedIdx = 0) && idx < terminatingIdx then - idx <- idx + 1 - - if maybeSkipping then - // Skip can only is only checked at the start of the sequence, so once - // triggered, we stay triggered. - maybeSkipping <- isSkipping () - - if maybeSkipping then - moveNext () - elif seqComponent.ProcessNext (f idx) then - true - else - moveNext () - elif (result.HaltedIdx = 0) && idx = System.Int32.MaxValue then - raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) - else - result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx - false - - interface IEnumerator with - member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess - moveNext () - - type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:ISeqFactory<'T,'U>) = - inherit Enumerable.EnumerableBase<'U>() - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - - interface ISeq<'U> with - member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) - - member this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = - let terminatingIdx = getTerminatingIdx count - ForEach.execute createResult current (ForEach.init f terminatingIdx) - - let upto lastOption f = - match lastOption with - | Some b when b<0 -> failwith "library implementation error: upto can never be called with a negative value" - | _ -> - let unstarted = -1 // index value means unstarted (and no valid index) - let completed = -2 // index value means completed (and no valid index) - let unreachable = -3 // index is unreachable from 0,1,2,3,... - let finalIndex = match lastOption with - | Some b -> b // here b>=0, a valid end value. - | None -> unreachable // run "forever", well as far as Int32.MaxValue since indexing with a bounded type. - // The Current value for a valid index is "f i". - // Lazy<_> values are used as caches, to store either the result or an exception if thrown. - // These "Lazy<_>" caches are created only on the first call to current and forced immediately. - // The lazy creation of the cache nodes means enumerations that skip many Current values are not delayed by GC. - // For example, the full enumeration of Seq.initInfinite in the tests. - // state - let index = ref unstarted - // a Lazy node to cache the result/exception - let current = ref (Unchecked.defaultof<_>) - let setIndex i = index := i; current := (Unchecked.defaultof<_>) // cache node unprimed, initialised on demand. - let getCurrent() = - if !index = unstarted then notStarted() - if !index = completed then alreadyFinished() - match box !current with - | null -> current := Lazy<_>.Create(fun () -> f !index) - | _ -> () - // forced or re-forced immediately. - (!current).Force() - { new IEnumerator<'U> with - member x.Current = getCurrent() - interface IEnumerator with - member x.Current = box (getCurrent()) - member x.MoveNext() = - if !index = completed then - false - elif !index = unstarted then - setIndex 0 - true - else ( - if !index = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) - if !index = finalIndex then - false - else - setIndex (!index + 1) - true - ) - member self.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = () } - - type EnumerableDecider<'T>(count:Nullable, f:int->'T) = - inherit Enumerable.EnumerableBase<'T>() - - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = - // we defer back to the original implementation as, as it's quite idiomatic in it's decision - // to calculate Current in a lazy fashion. I doubt anyone is really using this functionality - // in the way presented, but it's possible. - upto (if count.HasValue then Some (count.Value-1) else None) f - - interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable<'T,'V>(count, f, next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (upcastEnumerable this)) - - open RuntimeHelpers - - [] - let toComposer (source:seq<'T>) : ISeq<'T> = - checkNonNull "source" source - match source with - | :? ISeq<'T> as s -> s - | :? array<'T> as a -> upcastSeq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) - | :? list<'T> as a -> upcastSeq (List.Enumerable(a, IdentityFactory.Instance)) - | _ -> upcastSeq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) - - let inline foreach f (source:ISeq<_>) = - source.ForEach f - - let inline compose factory (source:ISeq<'T>) = - source.Compose factory - - [] - let empty<'T> = EmptyEnumerable.Enumerable<'T>.Instance - - [] - let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> = - upcastSeq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) - - [] - let initInfinite<'T> (f:int->'T) : ISeq<'T> = - upcastSeq (new Init.EnumerableDecider<'T>(Nullable (), f)) - - [] - let init<'T> (count:int) (f:int->'T) : ISeq<'T> = - if count < 0 then invalidArgInputMustBeNonNegative "count" count - elif count = 0 then empty else - upcastSeq (new Init.EnumerableDecider<'T>(Nullable count, f)) - - [] - let iter f (source:ISeq<'T>) = - source - |> foreach (fun _ -> - { new Consumer<'T,'T> () with - override this.ProcessNext value = - f value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> ignore - - [] - let tryItem i (source:ISeq<'T>) = - if i < 0 then None else - source - |> foreach (fun halt -> - { new Folder<'T, Values>> (Values<_,_> (0, None)) with - override this.ProcessNext value = - if this.Value._1 = i then - this.Value._2 <- Some value - halt () - else - this.Value._1 <- this.Value._1 + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun item -> item.Value._2 - - [] - let iteri f (source:ISeq<'T>) = - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f - - source - |> foreach (fun _ -> - { new Folder<'T, int> (0) with - override this.ProcessNext value = - f.Invoke(this.Value, value) - this.Value <- this.Value + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> ignore - - [] - let exists f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, bool> (false) with - override this.ProcessNext value = - if f value then - this.Value <- true - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun exists -> exists.Value - - [] - let inline contains element (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, bool> (false) with - override this.ProcessNext value = - if element = value then - this.Value <- true - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun contains -> contains.Value - - [] - let forall f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, bool> (true) with - override this.ProcessNext value = - if not (f value) then - this.Value <- false - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun forall -> forall.Value - - [] - let filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = - source - |> compose (FilterFactory f) - - [] - let map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = - source - |> compose (MapFactory f) - - [] - let mapi f source = - source - |> compose (MapiFactory f) - - [] - let choose f source = - source - |> compose (ChooseFactory f) - - [] - let indexed source = - source - |> compose (MapiFactory (fun i x -> i,x)) - - [] - let tryPick f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, Option<'U>> (None) with - override this.ProcessNext value = - match f value with - | (Some _) as some -> - this.Value <- some - halt () - | None -> () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun pick -> pick.Value - - [] - let tryFind f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, Option<'T>> (None) with - override this.ProcessNext value = - if f value then - this.Value <- Some value - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun find -> find.Value - - #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions #else #endif - open Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers - let mkDelayedSeq (f: unit -> IEnumerable<'T>) = mkSeq (fun () -> f().GetEnumerator()) let inline indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) [] - let toComposer (source:seq<'T>): Composer.Internal.ISeq<'T> = - Composer.toComposer source + let toComposer (source:seq<'T>): Composer.Core.ISeq<'T> = + Composer.Seq.toComposer source let inline foreach f (source:seq<_>) = - Composer.foreach f (toComposer source) + Composer.Seq.foreach f (toComposer source) [] let delay f = mkDelayedSeq f [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> = - Composer.unfold generator state + Composer.Seq.unfold generator state |> Composer.Helpers.upcastEnumerable [] @@ -1735,24 +58,24 @@ namespace Microsoft.FSharp.Collections [] let initInfinite<'T> (f:int->'T) : IEnumerable<'T> = - Composer.initInfinite f + Composer.Seq.initInfinite f |> Composer.Helpers.upcastEnumerable [] let init<'T> (count:int) (f:int->'T) : IEnumerable<'T> = - Composer.init count f + Composer.Seq.init count f |> Composer.Helpers.upcastEnumerable [] let iter f (source : seq<'T>) = - Composer.iter f (toComposer source) + Composer.Seq.iter f (toComposer source) [] let item i (source : seq<'T>) = if i < 0 then invalidArgInputMustBeNonNegative "index" i else source |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values<_,_,_> (0, false, Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values<_,_,_> (0, false, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 = i then this.Value._2 <- true @@ -1772,26 +95,26 @@ namespace Microsoft.FSharp.Collections [] let tryItem i (source:seq<'T>) = - Composer.tryItem i (toComposer source) + Composer.Seq.tryItem i (toComposer source) [] let nth i (source : seq<'T>) = item i source [] let iteri f (source:seq<'T>) = - Composer.iteri f (toComposer source) + Composer.Seq.iteri f (toComposer source) [] let exists f (source:seq<'T>) = - Composer.exists f (toComposer source) + Composer.Seq.exists f (toComposer source) [] let inline contains element (source:seq<'T>) = - Composer.contains element (toComposer source) + Composer.Seq.contains element (toComposer source) [] let forall f (source:seq<'T>) = - Composer.forall f (toComposer source) + Composer.Seq.forall f (toComposer source) [] let iter2 f (source1 : seq<_>) (source2 : seq<_>) = @@ -1802,7 +125,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<_,_> () with + { new Composer.Core.Folder<_,_> () with override this.ProcessNext value = if (e2.MoveNext()) then f.Invoke(value, e2.Current) @@ -1820,7 +143,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<_,int> (0) with + { new Composer.Core.Folder<_,int> (0) with override this.ProcessNext value = if (e2.MoveNext()) then f.Invoke(this.Value, value, e2.Current) @@ -1840,14 +163,14 @@ namespace Microsoft.FSharp.Collections let private seqFactory createSeqComponent (source:seq<'T>) = checkNonNull "source" source match source with - | :? Composer.Internal.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose createSeqComponent) - | :? array<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.Array.create a createSeqComponent) - | :? list<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.List.create a createSeqComponent) - | _ -> Composer.Helpers.upcastEnumerable (Composer.Enumerable.create source createSeqComponent) + | :? Composer.Core.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose createSeqComponent) + | :? array<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.Seq.Array.create a createSeqComponent) + | :? list<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.Seq.List.create a createSeqComponent) + | _ -> Composer.Helpers.upcastEnumerable (Composer.Seq.Enumerable.create source createSeqComponent) [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = - Composer.filter f (toComposer source) + Composer.Seq.filter f (toComposer source) |> Composer.Helpers.upcastEnumerable [] @@ -1855,40 +178,40 @@ namespace Microsoft.FSharp.Collections [] let map<'T,'U> (f:'T->'U) (source:seq<'T>) : seq<'U> = - Composer.map f (toComposer source) + Composer.Seq.map f (toComposer source) |> Composer.Helpers.upcastEnumerable [] let mapi f source = - Composer.mapi f (toComposer source) + Composer.Seq.mapi f (toComposer source) |> Composer.Helpers.upcastEnumerable [] let mapi2 f source1 source2 = checkNonNull "source2" source2 - source1 |> seqFactory (Composer.Mapi2Factory (f, source2)) + source1 |> seqFactory (Composer.Seq.Mapi2Factory (f, source2)) [] let map2<'T,'U,'V> (f:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = checkNonNull "source1" source1 match source1 with - | :? Composer.Internal.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose (Composer.Map2FirstFactory (f, source2))) - | _ -> source2 |> seqFactory (Composer.Map2SecondFactory (f, source1)) + | :? Composer.Core.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose (Composer.Seq.Map2FirstFactory (f, source2))) + | _ -> source2 |> seqFactory (Composer.Seq.Map2SecondFactory (f, source1)) [] let map3 f source1 source2 source3 = checkNonNull "source2" source2 checkNonNull "source3" source3 - source1 |> seqFactory (Composer.Map3Factory (f, source2, source3)) + source1 |> seqFactory (Composer.Seq.Map3Factory (f, source2, source3)) [] let choose f source = - Composer.choose f (toComposer source) + Composer.Seq.choose f (toComposer source) |> Composer.Helpers.upcastEnumerable [] let indexed source = - Composer.indexed (toComposer source) + Composer.Seq.indexed (toComposer source) |> Composer.Helpers.upcastEnumerable [] @@ -1906,7 +229,7 @@ namespace Microsoft.FSharp.Collections [] let tryPick f (source : seq<'T>) = - Composer.tryPick f (toComposer source) + Composer.Seq.tryPick f (toComposer source) [] let pick f source = @@ -1916,7 +239,7 @@ namespace Microsoft.FSharp.Collections [] let tryFind f (source : seq<'T>) = - Composer.tryFind f (toComposer source) + Composer.Seq.tryFind f (toComposer source) [] let find f source = @@ -1929,7 +252,7 @@ namespace Microsoft.FSharp.Collections if count < 0 then invalidArgInputMustBeNonNegative "count" count (* Note: don't create or dispose any IEnumerable if n = 0 *) if count = 0 then empty else - source |> seqFactory (Composer.TakeFactory count) + source |> seqFactory (Composer.Seq.TakeFactory count) [] let isEmpty (source : seq<'T>) = @@ -1945,7 +268,7 @@ namespace Microsoft.FSharp.Collections [] let concat (sources:seq<#seq<'T>>) : seq<'T> = checkNonNull "sources" sources - upcast Composer.Enumerable.ConcatEnumerable sources + upcast Composer.Seq.Enumerable.ConcatEnumerable sources [] let length (source : seq<'T>) = @@ -1967,7 +290,7 @@ namespace Microsoft.FSharp.Collections source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,'State> (x) with + { new Composer.Core.Folder<'T,'State> (x) with override this.ProcessNext value = this.Value <- f.Invoke (this.Value, value) Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) @@ -1982,7 +305,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<_,'State> (state) with + { new Composer.Core.Folder<_,'State> (state) with override this.ProcessNext value = if (e2.MoveNext()) then this.Value <- f.Invoke(this.Value, value, e2.Current) @@ -1997,7 +320,7 @@ namespace Microsoft.FSharp.Collections source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2021,8 +344,8 @@ namespace Microsoft.FSharp.Collections checkNonNull "source1" source1 checkNonNull "source2" source2 match source1 with - | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Append source2 - | _ -> Composer.Helpers.upcastEnumerable (new Composer.Enumerable.AppendEnumerable<_>([source2; source1])) + | :? Composer.Seq.Enumerable.EnumerableBase<'T> as s -> s.Append source2 + | _ -> Composer.Helpers.upcastEnumerable (new Composer.Seq.Enumerable.AppendEnumerable<_>([source2; source1])) [] @@ -2037,7 +360,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<'T,int> (0) with + { new Composer.Core.Folder<'T,int> (0) with override this.ProcessNext value = if not (e2.MoveNext()) then this.Value <- 1 @@ -2066,7 +389,7 @@ namespace Microsoft.FSharp.Collections [] let ofArray (source : 'T array) = checkNonNull "source" source - Composer.Helpers.upcastEnumerable (Composer.Array.createId source) + Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createId source) [] let toArray (source : seq<'T>) = @@ -2120,17 +443,17 @@ namespace Microsoft.FSharp.Collections [] let truncate n (source: seq<'T>) = if n <= 0 then empty else - source |> seqFactory (Composer.TruncateFactory n) + source |> seqFactory (Composer.Seq.TruncateFactory n) [] let pairwise<'T> (source:seq<'T>) : seq<'T*'T> = - source |> seqFactory (Composer.PairwiseFactory ()) + source |> seqFactory (Composer.Seq.PairwiseFactory ()) [] let scan<'T,'State> f (z:'State) (source : seq<'T>): seq<'State> = let first = [|z|] :> IEnumerable<'State> - let rest = source |> seqFactory (Composer.ScanFactory (f, z)) - upcast Composer.Enumerable.ConcatEnumerable [|first; rest;|] + let rest = source |> seqFactory (Composer.Seq.ScanFactory (f, z)) + upcast Composer.Seq.Enumerable.ConcatEnumerable [|first; rest;|] [] let tryFindBack f (source : seq<'T>) = @@ -2154,7 +477,7 @@ namespace Microsoft.FSharp.Collections let tryFindIndex p (source:seq<_>) = source |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values, int>> (Composer.Internal.Values<_,_>(None, 0)) with + { new Composer.Core.Folder<'T, Composer.Core.Values, int>> (Composer.Core.Values<_,_>(None, 0)) with override this.ProcessNext value = if p value then this.Value._1 <- Some(this.Value._2) @@ -2185,7 +508,7 @@ namespace Microsoft.FSharp.Collections let windowed windowSize (source: seq<_>) = if windowSize <= 0 then invalidArgFmt "windowSize" "{0}\nwindowSize = {1}" [|SR.GetString SR.inputMustBePositive; windowSize|] - source |> seqFactory (Composer.WindowedFactory (windowSize)) + source |> seqFactory (Composer.Seq.WindowedFactory (windowSize)) [] let cache (source : seq<'T>) = @@ -2289,7 +612,7 @@ namespace Microsoft.FSharp.Collections let groupByValueType (keyf:'T->'Key) (seq:seq<'T>) = seq |> groupByImpl HashIdentity.Structural<'Key> keyf id // Wrap a StructBox around all keys in case the key type is itself a type using null as a representation - let groupByRefType (keyf:'T->'Key) (seq:seq<'T>) = seq |> groupByImpl StructBox<'Key>.Comparer (fun t -> StructBox (keyf t)) (fun sb -> sb.Value) + let groupByRefType (keyf:'T->'Key) (seq:seq<'T>) = seq |> groupByImpl RuntimeHelpers.StructBox<'Key>.Comparer (fun t -> RuntimeHelpers.StructBox (keyf t)) (fun sb -> sb.Value) [] let groupBy (keyf:'T->'Key) (seq:seq<'T>) = @@ -2303,11 +626,11 @@ namespace Microsoft.FSharp.Collections [] let distinct source = - source |> seqFactory (Composer.DistinctFactory ()) + source |> seqFactory (Composer.Seq.DistinctFactory ()) [] let distinctBy keyf source = - source |> seqFactory (Composer.DistinctByFactory keyf) + source |> seqFactory (Composer.Seq.DistinctByFactory keyf) [] let sortBy keyf source = @@ -2316,7 +639,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceBy keyf array array - Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedSort) + Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedSort) [] let sort source = @@ -2325,7 +648,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlace array array - Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedSort) + Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedSort) [] let sortWith f source = @@ -2334,7 +657,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceWith f array array - Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedSort) + Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedSort) [] let inline sortByDescending keyf source = @@ -2367,7 +690,7 @@ namespace Microsoft.FSharp.Collections let countByValueType (keyf:'T->'Key) (seq:seq<'T>) = seq |> countByImpl HashIdentity.Structural<'Key> keyf id // Wrap a StructBox around all keys in case the key type is itself a type using null as a representation - let countByRefType (keyf:'T->'Key) (seq:seq<'T>) = seq |> countByImpl StructBox<'Key>.Comparer (fun t -> StructBox (keyf t)) (fun sb -> sb.Value) + let countByRefType (keyf:'T->'Key) (seq:seq<'T>) = seq |> countByImpl RuntimeHelpers.StructBox<'Key>.Comparer (fun t -> RuntimeHelpers.StructBox (keyf t)) (fun sb -> sb.Value) [] let countBy (keyf:'T->'Key) (source:seq<'T>) = @@ -2385,7 +708,7 @@ namespace Microsoft.FSharp.Collections let inline sum (source:seq<'a>) : 'a = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'a,'a> (LanguagePrimitives.GenericZero) with + { new Composer.Core.Folder<'a,'a> (LanguagePrimitives.GenericZero) with override this.ProcessNext value = this.Value <- Checked.(+) this.Value value Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) @@ -2395,7 +718,7 @@ namespace Microsoft.FSharp.Collections let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + { new Composer.Core.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with override this.ProcessNext value = this.Value <- Checked.(+) this.Value (f value) Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) @@ -2405,7 +728,7 @@ namespace Microsoft.FSharp.Collections let inline average (source: seq< ^a>) : ^a = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'a, Composer.Internal.Values<'a, int>> (Composer.Internal.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + { new Composer.Core.Folder<'a, Composer.Core.Values<'a, int>> (Composer.Core.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 value this.Value._2 <- this.Value._2 + 1 @@ -2420,7 +743,7 @@ namespace Microsoft.FSharp.Collections let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,Composer.Internal.Values<'U, int>> (Composer.Internal.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + { new Composer.Core.Folder<'T,Composer.Core.Values<'U, int>> (Composer.Core.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 (f value) this.Value._2 <- this.Value._2 + 1 @@ -2435,7 +758,7 @@ namespace Microsoft.FSharp.Collections let inline min (source: seq<_>) = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2454,7 +777,7 @@ namespace Microsoft.FSharp.Collections let inline minBy (f : 'T -> 'U) (source: seq<'T>) : 'T = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with override this.ProcessNext value = match this.Value._1, f value with | true, valueU -> @@ -2493,7 +816,7 @@ namespace Microsoft.FSharp.Collections let inline max (source: seq<_>) = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2512,7 +835,7 @@ namespace Microsoft.FSharp.Collections let inline maxBy (f : 'T -> 'U) (source: seq<'T>) : 'T = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with override this.ProcessNext value = match this.Value._1, f value with | true, valueU -> @@ -2550,15 +873,15 @@ namespace Microsoft.FSharp.Collections *) [] let takeWhile p (source: seq<_>) = - source |> seqFactory (Composer.TakeWhileFactory p) + source |> seqFactory (Composer.Seq.TakeWhileFactory p) [] let skip count (source: seq<_>) = - source |> seqFactory (Composer.SkipFactory count) + source |> seqFactory (Composer.Seq.SkipFactory count) [] let skipWhile p (source: seq<_>) = - source |> seqFactory (Composer.SkipWhileFactory p) + source |> seqFactory (Composer.Seq.SkipWhileFactory p) [] let forall2 p (source1: seq<_>) (source2: seq<_>) = @@ -2569,7 +892,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<_,bool> (true) with + { new Composer.Core.Folder<_,bool> (true) with override this.ProcessNext value = if (e2.MoveNext()) then if not (p.Invoke(value, e2.Current)) then @@ -2589,7 +912,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<_,bool> (false) with + { new Composer.Core.Folder<_,bool> (false) with override this.ProcessNext value = if (e2.MoveNext()) then if p.Invoke(value, e2.Current) then @@ -2604,7 +927,7 @@ namespace Microsoft.FSharp.Collections let tryHead (source : seq<_>) = source |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Option<'T>> (None) with + { new Composer.Core.Folder<'T, Option<'T>> (None) with override this.ProcessNext value = this.Value <- Some value halt () @@ -2619,13 +942,13 @@ namespace Microsoft.FSharp.Collections [] let tail (source: seq<'T>) = - source |> seqFactory (Composer.TailFactory ()) + source |> seqFactory (Composer.Seq.TailFactory ()) [] let tryLast (source : seq<_>) = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values(true, Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2647,7 +970,7 @@ namespace Microsoft.FSharp.Collections let exactlyOne (source : seq<_>) = source |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values(true, Unchecked.defaultof<'T>, false)) with + { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values(true, Unchecked.defaultof<'T>, false)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2671,7 +994,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.Reverse array array - Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedReverse) + Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedReverse) [] let permute f (source:seq<_>) = @@ -2680,7 +1003,7 @@ namespace Microsoft.FSharp.Collections source |> toArray |> Array.permute f - Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedPermute) + Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedPermute) [] let mapFold<'T,'State,'Result> (f: 'State -> 'T -> 'Result * 'State) acc source = @@ -2698,7 +1021,7 @@ namespace Microsoft.FSharp.Collections [] let except (itemsToExclude: seq<'T>) (source: seq<'T>) = checkNonNull "itemsToExclude" itemsToExclude - source |> seqFactory (Composer.ExceptFactory itemsToExclude) + source |> seqFactory (Composer.Seq.ExceptFactory itemsToExclude) [] let chunkBySize chunkSize (source : seq<_>) = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index 94dbb8bcc1a..f06c676e4de 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -13,75 +13,6 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = - module Composer = - module Internal = - /// PipeIdx denotes the index of the element within the pipeline. 0 denotes the - /// source of the chain. - type PipeIdx = int - type ``PipeIdx?`` = Nullable - - /// ICompletionChaining is used to correctly handle cleaning up of the pipeline. A - /// base implementation is provided in Consumer, and should not be overwritten. Consumer - /// provides it's own OnComplete and OnDispose function which should be used to handle - /// a particular consumers cleanup. - type ICompletionChaining = - /// OnComplete is used to determine if the object has been processed correctly, - /// and possibly throw exceptions to denote incorrect application (i.e. such as a Take - /// operation which didn't have a source at least as large as was required). It is - /// not called in the case of an exception being thrown whilst the stream is still - /// being processed. - abstract OnComplete : PipeIdx -> unit - /// OnDispose is used to cleanup the stream. It is always called at the last operation - /// after the enumeration has completed. - abstract OnDispose : unit -> unit - - type IOutOfBand = - abstract StopFurtherProcessing : PipeIdx -> unit - - /// Consumer is the base class of all elements within the pipeline - [] - type Consumer<'T,'U> = - interface ICompletionChaining - new : unit -> Consumer<'T,'U> - abstract member ProcessNext : input:'T -> bool - abstract member OnComplete : PipeIdx -> unit - abstract member OnDispose : unit -> unit - - /// Values is a mutable struct. It can be embedded within the folder type - /// if two values are required for the calculation. - [] - type Values<'a,'b> = - new : a:'a * b:'b -> Values<'a,'b> - val mutable _1: 'a - val mutable _2: 'b - - /// Values is a mutable struct. It can be embedded within the folder type - /// if three values are required for the calculation. - [] - type Values<'a,'b,'c> = - new : a:'a * b:'b * c:'c -> Values<'a,'b,'c> - val mutable _1: 'a - val mutable _2: 'b - val mutable _3: 'c - - /// Folder is a base class to assist with fold-like operations. It's intended usage - /// is as a base class for an object expression that will be used from within - /// the ForEach function. - [] - type Folder<'T,'U> = - inherit Consumer<'T,'T> - new : init:'U -> Folder<'T,'U> - val mutable Value: 'U - - type ISeqFactory<'T,'U> = - abstract member Create : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> - abstract member PipeIdx : PipeIdx - - type ISeq<'T> = - inherit System.Collections.Generic.IEnumerable<'T> - abstract member Compose : ISeqFactory<'T,'U> -> ISeq<'U> - abstract member ForEach : f:((unit -> unit) -> 'a) -> 'a when 'a :> Consumer<'T,'T> - /// Returns a new sequence that contains the cartesian product of the two input sequences. /// The first sequence. /// The second sequence. @@ -1273,7 +1204,7 @@ namespace Microsoft.FSharp.Collections /// /// Thrown when the input sequence is null. [] - val toComposer : source:seq<'T> -> Composer.Internal.ISeq<'T> + val toComposer : source:seq<'T> -> Composer.Core.ISeq<'T> /// Builds a list from the given collection. /// @@ -1419,98 +1350,4 @@ namespace Microsoft.FSharp.Collections /// /// Thrown when any of the input sequences is null. [] - val zip3: source1:seq<'T1> -> source2:seq<'T2> -> source3:seq<'T3> -> seq<'T1 * 'T2 * 'T3> - -namespace Microsoft.FSharp.Core.CompilerServices - - open System - open System.Collections - open System.Collections.Generic - open Microsoft.FSharp.Core - open Microsoft.FSharp.Collections - - - [] - /// A group of functions used as part of the compiled representation of F# sequence expressions. - module RuntimeHelpers = - - [] - type internal StructBox<'T when 'T : equality> = - new : value:'T -> StructBox<'T> - member Value : 'T - static member Comparer : IEqualityComparer> - - /// The F# compiler emits calls to this function to - /// implement the while operator for F# sequence expressions. - /// - /// A function that indicates whether iteration should continue. - /// The input sequence. - /// - /// The result sequence. - val EnumerateWhile : guard:(unit -> bool) -> source:seq<'T> -> seq<'T> - - /// The F# compiler emits calls to this function to - /// implement the try/finally operator for F# sequence expressions. - /// - /// The input sequence. - /// A computation to be included in an enumerator's Dispose method. - /// - /// The result sequence. - val EnumerateThenFinally : source:seq<'T> -> compensation:(unit -> unit) -> seq<'T> - - /// The F# compiler emits calls to this function to implement the compiler-intrinsic - /// conversions from untyped System.Collections.IEnumerable sequences to typed sequences. - /// - /// An initializer function. - /// A function to iterate and test if end of sequence is reached. - /// A function to retrieve the current element. - /// - /// The resulting typed sequence. - val EnumerateFromFunctions: create:(unit -> 'T) -> moveNext:('T -> bool) -> current:('T -> 'U) -> seq<'U> - - /// The F# compiler emits calls to this function to implement the use operator for F# sequence - /// expressions. - /// - /// The resource to be used and disposed. - /// The input sequence. - /// - /// The result sequence. - val EnumerateUsing : resource:'T -> source:('T -> 'Collection) -> seq<'U> when 'T :> IDisposable and 'Collection :> seq<'U> - - /// Creates an anonymous event with the given handlers. - /// - /// A function to handle adding a delegate for the event to trigger. - /// A function to handle removing a delegate that the event triggers. - /// A function to produce the delegate type the event can trigger. - /// - /// The initialized event. - val CreateEvent : addHandler : ('Delegate -> unit) -> removeHandler : ('Delegate -> unit) -> createHandler : ((obj -> 'Args -> unit) -> 'Delegate) -> Microsoft.FSharp.Control.IEvent<'Delegate,'Args> - - [] - /// The F# compiler emits implementations of this type for compiled sequence expressions. - type GeneratedSequenceBase<'T> = - /// The F# compiler emits implementations of this type for compiled sequence expressions. - /// - /// A new sequence generator for the expression. - new : unit -> GeneratedSequenceBase<'T> - /// The F# compiler emits implementations of this type for compiled sequence expressions. - /// - /// A new enumerator for the sequence. - abstract GetFreshEnumerator : unit -> IEnumerator<'T> - /// The F# compiler emits implementations of this type for compiled sequence expressions. - /// - /// A reference to the sequence. - /// - /// A 0, 1, and 2 respectively indicate Stop, Yield, and Goto conditions for the sequence generator. - abstract GenerateNext : result:byref> -> int - /// The F# compiler emits implementations of this type for compiled sequence expressions. - abstract Close: unit -> unit - /// The F# compiler emits implementations of this type for compiled sequence expressions. - abstract CheckClose: bool - /// The F# compiler emits implementations of this type for compiled sequence expressions. - abstract LastGenerated : 'T - interface IEnumerable<'T> - interface IEnumerable - interface IEnumerator<'T> - interface IEnumerator - + val zip3: source1:seq<'T1> -> source2:seq<'T2> -> source3:seq<'T3> -> seq<'T1 * 'T2 * 'T3> \ No newline at end of file diff --git a/src/fsharp/FSharp.Core/seqcomposer.fs b/src/fsharp/FSharp.Core/seqcomposer.fs new file mode 100644 index 00000000000..3f36e2c1469 --- /dev/null +++ b/src/fsharp/FSharp.Core/seqcomposer.fs @@ -0,0 +1,1286 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.FSharp.Collections + + open System + open System.Diagnostics + open System.Collections + open System.Collections.Generic + open System.Reflection + open Microsoft.FSharp.Core + open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators + open Microsoft.FSharp.Core.Operators + open Microsoft.FSharp.Core.CompilerServices + open Microsoft.FSharp.Control + open Microsoft.FSharp.Collections + open Microsoft.FSharp.Primitives.Basics + + [] + module Composer = + open IEnumerator + + module Core = + type PipeIdx = int + type ``PipeIdx?`` = Nullable + let emptyPipeIdx = Nullable () + let inline getPipeIdx (maybePipeIdx:``PipeIdx?``) = if maybePipeIdx.HasValue then maybePipeIdx.Value else 1 + let inline makePipeIdx (pipeIdx:PipeIdx) = Nullable pipeIdx + + type ICompletionChaining = + abstract OnComplete : PipeIdx -> unit + abstract OnDispose : unit -> unit + + type IOutOfBand = + abstract StopFurtherProcessing : PipeIdx -> unit + + [] + type Consumer<'T,'U> () = + abstract ProcessNext : input:'T -> bool + + abstract OnComplete : PipeIdx -> unit + abstract OnDispose : unit -> unit + + default __.OnComplete _ = () + default __.OnDispose () = () + + interface ICompletionChaining with + member this.OnComplete terminatingIdx = + this.OnComplete terminatingIdx + + member this.OnDispose () = + try this.OnDispose () + finally () + + [] + type Values<'a,'b> = + val mutable _1 : 'a + val mutable _2 : 'b + + new (a:'a, b: 'b) = { + _1 = a + _2 = b + } + + [] + type Values<'a,'b,'c> = + val mutable _1 : 'a + val mutable _2 : 'b + val mutable _3 : 'c + + new (a:'a, b:'b, c:'c) = { + _1 = a + _2 = b + _3 = c + } + + [] + type Folder<'T, 'U> = + inherit Consumer<'T,'T> + + val mutable Value : 'U + + new (init) = { + inherit Consumer<'T,'T>() + Value = init + } + + type ISeqFactory<'T,'U> = + abstract PipeIdx : PipeIdx + abstract Create<'V> : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> + + type ISeq<'T> = + inherit IEnumerable<'T> + abstract member Compose<'U> : (ISeqFactory<'T,'U>) -> ISeq<'U> + abstract member ForEach<'consumer when 'consumer :> Consumer<'T,'T>> : f:((unit->unit)->'consumer) -> 'consumer + + open Core + + module internal Helpers = + // used for performance reasons; these are not recursive calls, so should be safe + // ** it should be noted that potential changes to the f# compiler may render this function + // ineffictive ** + let inline avoidTailCall boolean = match boolean with true -> true | false -> false + + // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality + // is fixed with the compiler then these functions can be removed. + let inline upcastSeq (t:#ISeq<'T>) : ISeq<'T> = (# "" t : ISeq<'T> #) + let inline upcastFactory (t:#ISeqFactory<'T,'U>) : ISeqFactory<'T,'U> = (# "" t : ISeqFactory<'T,'U> #) + let inline upcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) + let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) + let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) + let inline upcastICompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) + + open Helpers + + module internal Seq = + type [] SeqComponentFactory<'T,'U> (pipeIdx:``PipeIdx?``) = + new() = SeqComponentFactory<'T,'U> (emptyPipeIdx) + + interface ISeqFactory<'T,'U> with + member __.PipeIdx = getPipeIdx pipeIdx + member __.Create<'V> (_:IOutOfBand) (_:``PipeIdx?``) (_:Consumer<'U,'V>) : Consumer<'T,'V> = failwith "library implementation error: Create on base factory should not be called" + + and ComposedFactory<'T,'U,'V> private (first:ISeqFactory<'T,'U>, second:ISeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = + inherit SeqComponentFactory<'T,'V> (makePipeIdx secondPipeIdx) + + interface ISeqFactory<'T,'V> with + member this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'V,'W>) : Consumer<'T,'W> = + first.Create outOfBand pipeIdx (second.Create outOfBand (makePipeIdx secondPipeIdx) next) + + static member Combine (first:ISeqFactory<'T,'U>) (second:ISeqFactory<'U,'V>) : ISeqFactory<'T,'V> = + ComposedFactory(first, second, first.PipeIdx+1) |> upcastFactory + + and ChooseFactory<'T,'U> (filter:'T->option<'U>) = + inherit SeqComponentFactory<'T,'U> () + interface ISeqFactory<'T,'U> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) + + and DistinctFactory<'T when 'T: equality> () = + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) + + and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) + + and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) + + and FilterFactory<'T> (filter:'T->bool) = + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = + match next with + | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter + | _ -> upcast Filter (filter, next) + + and IdentityFactory<'T> () = + inherit SeqComponentFactory<'T,'T> () + static let singleton = IdentityFactory<'T>() + interface ISeqFactory<'T,'T> with + member __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next + static member Instance = singleton + + and MapFactory<'T,'U> (map:'T->'U) = + inherit SeqComponentFactory<'T,'U> () + interface ISeqFactory<'T,'U> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = + match next with + | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map + | _ -> upcast Map<_,_,_> (map, next) + + and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = + inherit SeqComponentFactory<'First,'U> () + interface ISeqFactory<'First,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, outOfBand, next, getPipeIdx pipeIdx) + + and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = + inherit SeqComponentFactory<'Second,'U> () + interface ISeqFactory<'Second,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, outOfBand, next, getPipeIdx pipeIdx) + + and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = + inherit SeqComponentFactory<'First,'U> () + interface ISeqFactory<'First,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, outOfBand, next, getPipeIdx pipeIdx) + + and MapiFactory<'T,'U> (mapi:int->'T->'U) = + inherit SeqComponentFactory<'T,'U> () + interface ISeqFactory<'T,'U> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Mapi (mapi, next) + + and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = + inherit SeqComponentFactory<'First,'U> () + interface ISeqFactory<'First,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, outOfBand, next, getPipeIdx pipeIdx) + + and PairwiseFactory<'T> () = + inherit SeqComponentFactory<'T,'T*'T> () + interface ISeqFactory<'T,'T*'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) + + and ScanFactory<'T,'State> (folder:'State->'T->'State, initialState:'State) = + inherit SeqComponentFactory<'T,'State> () + interface ISeqFactory<'T,'State> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) + + and SkipFactory<'T> (count:int) = + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, next) + + and SkipWhileFactory<'T> (predicate:'T->bool) = + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) + + and TakeWhileFactory<'T> (predicate:'T->bool) = + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, outOfBand, next, getPipeIdx pipeIdx) + + and TakeFactory<'T> (count:int) = + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, outOfBand, next, getPipeIdx pipeIdx) + + and TailFactory<'T> () = + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) + + and TruncateFactory<'T> (count:int) = + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, getPipeIdx pipeIdx) + + and WindowedFactory<'T> (windowSize:int) = + inherit SeqComponentFactory<'T, 'T[]> () + interface ISeqFactory<'T, 'T[]> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T[],'V>) : Consumer<'T,'V> = upcast Windowed (windowSize, next) + + and [] SeqComponent<'T,'U> (next:ICompletionChaining) = + inherit Consumer<'T,'U>() + + // Seq.init(Infinite)? lazily uses Current. The only Composer component that can do that is Skip + // and it can only do it at the start of a sequence + abstract Skipping : unit -> bool + + abstract CreateMap<'S> : map:('S->'T) -> SeqComponent<'S,'U> + abstract CreateFilter : filter:('T->bool) -> SeqComponent<'T,'U> + + interface ICompletionChaining with + member this.OnComplete terminatingIdx = + this.OnComplete terminatingIdx + next.OnComplete terminatingIdx + member this.OnDispose () = + try this.OnDispose () + finally next.OnDispose () + + default __.Skipping () = false + + default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) + default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) + + and Choose<'T,'U,'V> (choose:'T->option<'U>, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + match choose input with + | Some value -> avoidTailCall (next.ProcessNext value) + | None -> false + + and Distinct<'T,'V when 'T: equality> (next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) + + override __.ProcessNext (input:'T) : bool = + if hashSet.Add input then + avoidTailCall (next.ProcessNext input) + else + false + + and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) + + override __.ProcessNext (input:'T) : bool = + if hashSet.Add(keyFunction input) then + avoidTailCall (next.ProcessNext input) + else + false + + and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) + + override __.ProcessNext (input:'T) : bool = + if cached.Value.Add input then + avoidTailCall (next.ProcessNext input) + else + false + + and Filter<'T,'V> (filter:'T->bool, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) + + override __.ProcessNext (input:'T) : bool = + if filter input then + avoidTailCall (next.ProcessNext input) + else + false + + and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + if filter input then + avoidTailCall (next.ProcessNext (map input)) + else + false + + and Map<'T,'U,'V> (map:'T->'U, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) + + override __.ProcessNext (input:'T) : bool = + avoidTailCall (next.ProcessNext (map input)) + + and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = + inherit SeqComponent<'First,'V>(next) + + let input2 = enumerable2.GetEnumerator () + let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map + + override __.ProcessNext (input:'First) : bool = + if input2.MoveNext () then + avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) + else + outOfBand.StopFurtherProcessing pipeIdx + false + + override __.OnDispose () = + input2.Dispose () + + and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = + inherit SeqComponent<'Second,'V>(next) + + let input1 = enumerable1.GetEnumerator () + let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map + + override __.ProcessNext (input:'Second) : bool = + if input1.MoveNext () then + avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) + else + outOfBand.StopFurtherProcessing pipeIdx + false + + override __.OnDispose () = + input1.Dispose () + + and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = + inherit SeqComponent<'First,'V>(next) + + let input2 = enumerable2.GetEnumerator () + let input3 = enumerable3.GetEnumerator () + let map' = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt map + + override __.ProcessNext (input:'First) : bool = + if input2.MoveNext () && input3.MoveNext () then + avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) + else + outOfBand.StopFurtherProcessing pipeIdx + false + + override __.OnDispose () = + try input2.Dispose () + finally input3.Dispose () + + and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + let u = map input + if filter u then + avoidTailCall (next.ProcessNext u) + else + false + + and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable idx = 0 + let mapi' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt mapi + + override __.ProcessNext (input:'T) : bool = + idx <- idx + 1 + avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) + + and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = + inherit SeqComponent<'First,'V>(next) + + let mutable idx = 0 + let input2 = enumerable2.GetEnumerator () + let mapi2' = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt map + + override __.ProcessNext (input:'First) : bool = + if input2.MoveNext () then + idx <- idx + 1 + avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) + else + outOfBand.StopFurtherProcessing pipeIdx + false + + override __.OnDispose () = + input2.Dispose () + + and Pairwise<'T,'V> (next:Consumer<'T*'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable isFirst = true + let mutable lastValue = Unchecked.defaultof<'T> + + override __.ProcessNext (input:'T) : bool = + if isFirst then + lastValue <- input + isFirst <- false + false + else + let currentPair = lastValue, input + lastValue <- input + avoidTailCall (next.ProcessNext currentPair) + + and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:Consumer<'State,'V>) = + inherit SeqComponent<'T,'V>(next) + + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + let mutable foldResult = initialState + + override __.ProcessNext (input:'T) : bool = + foldResult <- f.Invoke(foldResult, input) + avoidTailCall (next.ProcessNext foldResult) + + and Skip<'T,'V> (skipCount:int, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable count = 0 + + override __.Skipping () = + if count < skipCount then + count <- count + 1 + true + else + false + + override __.ProcessNext (input:'T) : bool = + if count < skipCount then + count <- count + 1 + false + else + avoidTailCall (next.ProcessNext input) + + override __.OnComplete _ = + if count < skipCount then + let x = skipCount - count + invalidOpFmt "tried to skip {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + + and SkipWhile<'T,'V> (predicate:'T->bool, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable skip = true + + override __.ProcessNext (input:'T) : bool = + if skip then + skip <- predicate input + if skip then + false + else + avoidTailCall (next.ProcessNext input) + else + avoidTailCall (next.ProcessNext input) + + and Take<'T,'V> (takeCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipelineIdx:int) = + inherit Truncate<'T, 'V>(takeCount, outOfBand, next, pipelineIdx) + + override this.OnComplete terminatingIdx = + if terminatingIdx < pipelineIdx && this.Count < takeCount then + let x = takeCount - this.Count + invalidOpFmt "tried to take {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + + and TakeWhile<'T,'V> (predicate:'T->bool, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + if predicate input then + avoidTailCall (next.ProcessNext input) + else + outOfBand.StopFurtherProcessing pipeIdx + false + + and Tail<'T, 'V> (next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable first = true + + override __.ProcessNext (input:'T) : bool = + if first then + first <- false + false + else + avoidTailCall (next.ProcessNext input) + + override this.OnComplete _ = + if first then + invalidArg "source" (SR.GetString(SR.notEnoughElements)) + + and Truncate<'T,'V> (truncateCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = + inherit SeqComponent<'T,'V>(next) + + let mutable count = 0 + + member __.Count = count + + override __.ProcessNext (input:'T) : bool = + if count < truncateCount then + count <- count + 1 + if count = truncateCount then + outOfBand.StopFurtherProcessing pipeIdx + avoidTailCall (next.ProcessNext input) + else + outOfBand.StopFurtherProcessing pipeIdx + false + + and Windowed<'T,'V> (windowSize: int, next:Consumer<'T[],'V>) = + inherit SeqComponent<'T,'V>(next) + + let circularBuffer = Array.zeroCreateUnchecked windowSize + let mutable idx = 0 + + let mutable priming = windowSize - 1 + + override __.ProcessNext (input:'T) : bool = + circularBuffer.[idx] <- input + + idx <- idx + 1 + if idx = windowSize then + idx <- 0 + + if priming > 0 then + priming <- priming - 1 + false + else + if windowSize < 32 then + let window = Array.init windowSize (fun i -> circularBuffer.[(idx+i) % windowSize]) + avoidTailCall (next.ProcessNext window) + else + let window = Array.zeroCreateUnchecked windowSize + Array.Copy(circularBuffer, idx, window, 0, windowSize - idx) + Array.Copy(circularBuffer, 0, window, windowSize - idx, idx) + avoidTailCall (next.ProcessNext window) + + type SeqProcessNextStates = + | InProcess = 0 + | NotStarted = 1 + | Finished = 2 + + type Result<'T>() = + let mutable haltedIdx = 0 + + member val Current = Unchecked.defaultof<'T> with get, set + member val SeqState = SeqProcessNextStates.NotStarted with get, set + member __.HaltedIdx = haltedIdx + + interface IOutOfBand with + member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx + + // SetResult<> is used at the end of the chain of SeqComponents to assign the final value + type SetResult<'T> (result:Result<'T>) = + inherit Consumer<'T,'T>() + + override __.ProcessNext (input:'T) : bool = + result.Current <- input + true + + type OutOfBand() = + let mutable haltedIdx = 0 + interface IOutOfBand with member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx + member __.HaltedIdx = haltedIdx + + module ForEach = + let enumerable (enumerable:IEnumerable<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = + use enumerator = enumerable.GetEnumerator () + while (outOfBand.HaltedIdx = 0) && (enumerator.MoveNext ()) do + consumer.ProcessNext enumerator.Current |> ignore + + let array (array:array<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = + let mutable idx = 0 + while (outOfBand.HaltedIdx = 0) && (idx < array.Length) do + consumer.ProcessNext array.[idx] |> ignore + idx <- idx + 1 + + let list (alist:list<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = + let rec iterate lst = + match outOfBand.HaltedIdx, lst with + | 0, hd :: tl -> + consumer.ProcessNext hd |> ignore + iterate tl + | _ -> () + iterate alist + + let unfold (generator:'S->option<'T*'S>) state (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = + let rec iterate current = + match outOfBand.HaltedIdx, generator current with + | 0, Some (item, next) -> + consumer.ProcessNext item |> ignore + iterate next + | _ -> () + + iterate state + + let makeIsSkipping (consumer:Consumer<'T,'U>) = + match consumer with + | :? SeqComponent<'T,'U> as c -> c.Skipping + | _ -> fun () -> false + + let init f (terminatingIdx:int) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = + let mutable idx = -1 + let isSkipping = makeIsSkipping consumer + let mutable maybeSkipping = true + while (outOfBand.HaltedIdx = 0) && (idx < terminatingIdx) do + if maybeSkipping then + maybeSkipping <- isSkipping () + + if (not maybeSkipping) then + consumer.ProcessNext (f (idx+1)) |> ignore + + idx <- idx + 1 + + let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:ISeqFactory<'T,'U>) executeOn = + let pipeline = OutOfBand() + let result = f (fun () -> (pipeline:>IOutOfBand).StopFurtherProcessing (current.PipeIdx+1)) + let consumer = current.Create pipeline emptyPipeIdx result + try + executeOn pipeline consumer + (upcastICompletionChaining consumer).OnComplete pipeline.HaltedIdx + result + finally + (upcastICompletionChaining consumer).OnDispose () + + module Enumerable = + type Empty<'T>() = + let current () = failwith "library implementation error: Current should never be called" + interface IEnumerator<'T> with + member __.Current = current () + interface IEnumerator with + member __.Current = current () + member __.MoveNext () = false + member __.Reset (): unit = noReset () + interface IDisposable with + member __.Dispose () = () + + type EmptyEnumerators<'T>() = + static let element : IEnumerator<'T> = upcast (new Empty<'T> ()) + static member Element = element + + [] + type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ICompletionChaining) = + interface IDisposable with + member __.Dispose() : unit = + seqComponent.OnDispose () + + interface IEnumerator with + member this.Current : obj = box ((upcastEnumerator this)).Current + member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)" + member __.Reset () : unit = noReset () + + interface IEnumerator<'T> with + member __.Current = + if result.SeqState = SeqProcessNextStates.InProcess then result.Current + else + match result.SeqState with + | SeqProcessNextStates.NotStarted -> notStarted() + | SeqProcessNextStates.Finished -> alreadyFinished() + | _ -> failwith "library implementation error: all states should have been handled" + + and [] EnumerableBase<'T> () = + let derivedClassShouldImplement () = + failwith "library implementation error: derived class should implement (should be abstract)" + + abstract member Append : (seq<'T>) -> IEnumerable<'T> + + default this.Append source = upcastEnumerable (AppendEnumerable [this; source]) + + interface IEnumerable with + member this.GetEnumerator () : IEnumerator = + let genericEnumerable = upcastEnumerable this + let genericEnumerator = genericEnumerable.GetEnumerator () + upcastEnumeratorNonGeneric genericEnumerator + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement () + + interface ISeq<'T> with + member __.Compose _ = derivedClassShouldImplement () + member __.ForEach _ = derivedClassShouldImplement () + + and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit EnumeratorBase<'U>(result, seqComponent) + + let rec moveNext () = + if (result.HaltedIdx = 0) && source.MoveNext () then + if seqComponent.ProcessNext source.Current then + true + else + moveNext () + else + result.SeqState <- SeqProcessNextStates.Finished + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + false + + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext () + + interface IDisposable with + member __.Dispose() = + try + source.Dispose () + finally + (upcastICompletionChaining seqComponent).OnDispose () + + and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:ISeqFactory<'T,'U>) = + inherit EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) + + interface ISeq<'U> with + member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + upcastSeq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.enumerable enumerable) + + and ConcatEnumerator<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = + let mutable state = SeqProcessNextStates.NotStarted + let main = sources.GetEnumerator () + + let mutable active = EmptyEnumerators.Element + + let rec moveNext () = + if active.MoveNext () then + true + elif main.MoveNext () then + active.Dispose () + active <- main.Current.GetEnumerator () + moveNext () + else + state <- SeqProcessNextStates.Finished + false + + interface IEnumerator<'T> with + member __.Current = + if state = SeqProcessNextStates.InProcess then active.Current + else + match state with + | SeqProcessNextStates.NotStarted -> notStarted() + | SeqProcessNextStates.Finished -> alreadyFinished() + | _ -> failwith "library implementation error: all states should have been handled" + + interface IEnumerator with + member this.Current = box ((upcastEnumerator this)).Current + member __.MoveNext () = + state <- SeqProcessNextStates.InProcess + moveNext () + member __.Reset () = noReset () + + interface IDisposable with + member __.Dispose() = + main.Dispose () + active.Dispose () + + and AppendEnumerable<'T> (sources:list>) = + inherit EnumerableBase<'T>() + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = + upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) + + override this.Append source = + upcastEnumerable (AppendEnumerable (source :: sources)) + + interface ISeq<'T> with + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + upcastSeq (Enumerable<'T,'V>(this, next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) + + and ConcatEnumerable<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = + inherit EnumerableBase<'T>() + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = + upcastEnumerator (new ConcatEnumerator<_,_> (sources)) + + interface ISeq<'T> with + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + upcastSeq (Enumerable<'T,'V>(this, next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) + + let create enumerable current = + upcastSeq (Enumerable(enumerable, current)) + + module EmptyEnumerable = + type Enumerable<'T> () = + inherit Enumerable.EnumerableBase<'T>() + + static let singleton = Enumerable<'T>() :> ISeq<'T> + static member Instance = singleton + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>() + + override this.Append source = + upcastEnumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) + + interface ISeq<'T> with + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + upcastSeq (Enumerable.Enumerable<'T,'V>(this, next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) + + + + module Array = + type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + + let mutable idx = 0 + let mutable array = Unchecked.defaultof<_> + + let mutable initMoveNext = Unchecked.defaultof<_> + do + initMoveNext <- + fun () -> + result.SeqState <- SeqProcessNextStates.InProcess + array <- delayedArray () + initMoveNext <- ignore + + let rec moveNext () = + if (result.HaltedIdx = 0) && idx < array.Length then + idx <- idx+1 + if seqComponent.ProcessNext array.[idx-1] then + true + else + moveNext () + else + result.SeqState <- SeqProcessNextStates.Finished + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + false + + interface IEnumerator with + member __.MoveNext () = + initMoveNext () + moveNext () + + type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:ISeqFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + + interface ISeq<'U> with + member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + upcastSeq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.array (delayedArray ())) + + let createDelayed (delayedArray:unit->array<'T>) (current:ISeqFactory<'T,'U>) = + upcastSeq (Enumerable(delayedArray, current)) + + let create (array:array<'T>) (current:ISeqFactory<'T,'U>) = + createDelayed (fun () -> array) current + + let createDelayedId (delayedArray:unit -> array<'T>) = + createDelayed delayedArray IdentityFactory.Instance + + let createId (array:array<'T>) = + create array IdentityFactory.Instance + + module List = + type Enumerator<'T,'U>(alist:list<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + + let mutable list = alist + + let rec moveNext current = + match result.HaltedIdx, current with + | 0, head::tail -> + if seqComponent.ProcessNext head then + list <- tail + true + else + moveNext tail + | _ -> + result.SeqState <- SeqProcessNextStates.Finished + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + false + + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext list + + type Enumerable<'T,'U>(alist:list<'T>, current:ISeqFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + + interface ISeq<'U> with + member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + upcastSeq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.list alist) + + let create alist current = + upcastSeq (Enumerable(alist, current)) + + module Unfold = + type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + + let mutable current = state + + let rec moveNext () = + match result.HaltedIdx, generator current with + | 0, Some (item, nextState) -> + current <- nextState + if seqComponent.ProcessNext item then + true + else + moveNext () + | _ -> false + + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext () + + type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:ISeqFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + + interface ISeq<'U> with + member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + upcastSeq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.unfold generator state) + + module Init = + // The original implementation of "init" delayed the calculation of Current, and so it was possible + // to do MoveNext without it's value being calculated. + // I can imagine only two scenerios where that is possibly sane, although a simple solution is readily + // at hand in both cases. The first is that of an expensive generator function, where you skip the + // first n elements. The simple solution would have just been to have a map ((+) n) as the first operation + // instead. The second case would be counting elements, but that is only of use if you're not filtering + // or mapping or doing anything else (as that would cause Current to be evaluated!) and + // so you already know what the count is!! Anyway, someone thought it was a good idea, so + // I have had to add an extra function that is used in Skip to determine if we are touching + // Current or not. + + let getTerminatingIdx (count:Nullable) = + // we are offset by 1 to allow for values going up to System.Int32.MaxValue + // System.Int32.MaxValue is an illegal value for the "infinite" sequence + if count.HasValue then + count.Value - 1 + else + System.Int32.MaxValue + + type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + + let isSkipping = + ForEach.makeIsSkipping seqComponent + + let terminatingIdx = + getTerminatingIdx count + + let mutable maybeSkipping = true + let mutable idx = -1 + + let rec moveNext () = + if (result.HaltedIdx = 0) && idx < terminatingIdx then + idx <- idx + 1 + + if maybeSkipping then + // Skip can only is only checked at the start of the sequence, so once + // triggered, we stay triggered. + maybeSkipping <- isSkipping () + + if maybeSkipping then + moveNext () + elif seqComponent.ProcessNext (f idx) then + true + else + moveNext () + elif (result.HaltedIdx = 0) && idx = System.Int32.MaxValue then + raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) + else + result.SeqState <- SeqProcessNextStates.Finished + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + false + + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext () + + type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:ISeqFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + + interface ISeq<'U> with + member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + upcastSeq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + + member this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = + let terminatingIdx = getTerminatingIdx count + ForEach.execute createResult current (ForEach.init f terminatingIdx) + + let upto lastOption f = + match lastOption with + | Some b when b<0 -> failwith "library implementation error: upto can never be called with a negative value" + | _ -> + let unstarted = -1 // index value means unstarted (and no valid index) + let completed = -2 // index value means completed (and no valid index) + let unreachable = -3 // index is unreachable from 0,1,2,3,... + let finalIndex = match lastOption with + | Some b -> b // here b>=0, a valid end value. + | None -> unreachable // run "forever", well as far as Int32.MaxValue since indexing with a bounded type. + // The Current value for a valid index is "f i". + // Lazy<_> values are used as caches, to store either the result or an exception if thrown. + // These "Lazy<_>" caches are created only on the first call to current and forced immediately. + // The lazy creation of the cache nodes means enumerations that skip many Current values are not delayed by GC. + // For example, the full enumeration of Seq.initInfinite in the tests. + // state + let index = ref unstarted + // a Lazy node to cache the result/exception + let current = ref (Unchecked.defaultof<_>) + let setIndex i = index := i; current := (Unchecked.defaultof<_>) // cache node unprimed, initialised on demand. + let getCurrent() = + if !index = unstarted then notStarted() + if !index = completed then alreadyFinished() + match box !current with + | null -> current := Lazy<_>.Create(fun () -> f !index) + | _ -> () + // forced or re-forced immediately. + (!current).Force() + { new IEnumerator<'U> with + member x.Current = getCurrent() + interface IEnumerator with + member x.Current = box (getCurrent()) + member x.MoveNext() = + if !index = completed then + false + elif !index = unstarted then + setIndex 0 + true + else ( + if !index = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) + if !index = finalIndex then + false + else + setIndex (!index + 1) + true + ) + member self.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = () } + + type EnumerableDecider<'T>(count:Nullable, f:int->'T) = + inherit Enumerable.EnumerableBase<'T>() + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = + // we defer back to the original implementation as, as it's quite idiomatic in it's decision + // to calculate Current in a lazy fashion. I doubt anyone is really using this functionality + // in the way presented, but it's possible. + upto (if count.HasValue then Some (count.Value-1) else None) f + + interface ISeq<'T> with + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + upcastSeq (Enumerable<'T,'V>(count, f, next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (upcastEnumerable this)) + + [] + let toComposer (source:seq<'T>) : ISeq<'T> = + checkNonNull "source" source + match source with + | :? ISeq<'T> as s -> s + | :? array<'T> as a -> upcastSeq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) + | :? list<'T> as a -> upcastSeq (List.Enumerable(a, IdentityFactory.Instance)) + | _ -> upcastSeq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) + + let inline foreach f (source:ISeq<_>) = + source.ForEach f + + let inline compose factory (source:ISeq<'T>) = + source.Compose factory + + [] + let empty<'T> = EmptyEnumerable.Enumerable<'T>.Instance + + [] + let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> = + upcastSeq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) + + [] + let initInfinite<'T> (f:int->'T) : ISeq<'T> = + upcastSeq (new Init.EnumerableDecider<'T>(Nullable (), f)) + + [] + let init<'T> (count:int) (f:int->'T) : ISeq<'T> = + if count < 0 then invalidArgInputMustBeNonNegative "count" count + elif count = 0 then empty else + upcastSeq (new Init.EnumerableDecider<'T>(Nullable count, f)) + + [] + let iter f (source:ISeq<'T>) = + source + |> foreach (fun _ -> + { new Consumer<'T,'T> () with + override this.ProcessNext value = + f value + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> ignore + + [] + let tryItem i (source:ISeq<'T>) = + if i < 0 then None else + source + |> foreach (fun halt -> + { new Folder<'T, Values>> (Values<_,_> (0, None)) with + override this.ProcessNext value = + if this.Value._1 = i then + this.Value._2 <- Some value + halt () + else + this.Value._1 <- this.Value._1 + 1 + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun item -> item.Value._2 + + [] + let iteri f (source:ISeq<'T>) = + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f + + source + |> foreach (fun _ -> + { new Folder<'T, int> (0) with + override this.ProcessNext value = + f.Invoke(this.Value, value) + this.Value <- this.Value + 1 + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> ignore + + [] + let exists f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, bool> (false) with + override this.ProcessNext value = + if f value then + this.Value <- true + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun exists -> exists.Value + + [] + let inline contains element (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, bool> (false) with + override this.ProcessNext value = + if element = value then + this.Value <- true + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun contains -> contains.Value + + [] + let forall f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, bool> (true) with + override this.ProcessNext value = + if not (f value) then + this.Value <- false + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun forall -> forall.Value + + [] + let filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = + source + |> compose (FilterFactory f) + + [] + let map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = + source + |> compose (MapFactory f) + + [] + let mapi f source = + source + |> compose (MapiFactory f) + + [] + let choose f source = + source + |> compose (ChooseFactory f) + + [] + let indexed source = + source + |> compose (MapiFactory (fun i x -> i,x)) + + [] + let tryPick f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, Option<'U>> (None) with + override this.ProcessNext value = + match f value with + | (Some _) as some -> + this.Value <- some + halt () + | None -> () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun pick -> pick.Value + + [] + let tryFind f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, Option<'T>> (None) with + override this.ProcessNext value = + if f value then + this.Value <- Some value + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun find -> find.Value \ No newline at end of file diff --git a/src/fsharp/FSharp.Core/seqcomposer.fsi b/src/fsharp/FSharp.Core/seqcomposer.fsi new file mode 100644 index 00000000000..838cee6da37 --- /dev/null +++ b/src/fsharp/FSharp.Core/seqcomposer.fsi @@ -0,0 +1,757 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.FSharp.Collections + + open System + open System.Collections + open System.Collections.Generic + open Microsoft.FSharp.Core + open Microsoft.FSharp.Collections + + [] + module Composer = + module Core = + /// PipeIdx denotes the index of the element within the pipeline. 0 denotes the + /// source of the chain. + type PipeIdx = int + type ``PipeIdx?`` = Nullable + + /// ICompletionChaining is used to correctly handle cleaning up of the pipeline. A + /// base implementation is provided in Consumer, and should not be overwritten. Consumer + /// provides it's own OnComplete and OnDispose function which should be used to handle + /// a particular consumers cleanup. + type ICompletionChaining = + /// OnComplete is used to determine if the object has been processed correctly, + /// and possibly throw exceptions to denote incorrect application (i.e. such as a Take + /// operation which didn't have a source at least as large as was required). It is + /// not called in the case of an exception being thrown whilst the stream is still + /// being processed. + abstract OnComplete : PipeIdx -> unit + /// OnDispose is used to cleanup the stream. It is always called at the last operation + /// after the enumeration has completed. + abstract OnDispose : unit -> unit + + type IOutOfBand = + abstract StopFurtherProcessing : PipeIdx -> unit + + /// Consumer is the base class of all elements within the pipeline + [] + type Consumer<'T,'U> = + interface ICompletionChaining + new : unit -> Consumer<'T,'U> + abstract member ProcessNext : input:'T -> bool + abstract member OnComplete : PipeIdx -> unit + abstract member OnDispose : unit -> unit + override OnComplete : PipeIdx -> unit + override OnDispose : unit -> unit + + /// Values is a mutable struct. It can be embedded within the folder type + /// if two values are required for the calculation. + [] + type Values<'a,'b> = + new : a:'a * b:'b -> Values<'a,'b> + val mutable _1: 'a + val mutable _2: 'b + + /// Values is a mutable struct. It can be embedded within the folder type + /// if three values are required for the calculation. + [] + type Values<'a,'b,'c> = + new : a:'a * b:'b * c:'c -> Values<'a,'b,'c> + val mutable _1: 'a + val mutable _2: 'b + val mutable _3: 'c + + /// Folder is a base class to assist with fold-like operations. It's intended usage + /// is as a base class for an object expression that will be used from within + /// the ForEach function. + [] + type Folder<'T,'U> = + inherit Consumer<'T,'T> + new : init:'U -> Folder<'T,'U> + val mutable Value: 'U + + type ISeqFactory<'T,'U> = + abstract member Create : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> + abstract member PipeIdx : PipeIdx + + type ISeq<'T> = + inherit System.Collections.Generic.IEnumerable<'T> + abstract member Compose : ISeqFactory<'T,'U> -> ISeq<'U> + abstract member ForEach : f:((unit -> unit) -> 'a) -> 'a when 'a :> Consumer<'T,'T> + + open Core + + module internal Helpers = + val inline avoidTailCall : boolean:bool -> bool + val inline upcastSeq : t: #ISeq<'T> -> ISeq<'T> + val inline upcastFactory : + t: #ISeqFactory<'T,'U> -> ISeqFactory<'T,'U> + val inline upcastEnumerable : t:#IEnumerable<'T> -> IEnumerable<'T> + val inline upcastEnumerator : t:#IEnumerator<'T> ->IEnumerator<'T> + val inline upcastEnumeratorNonGeneric : + t:#IEnumerator -> IEnumerator + val inline upcastICompletionChaining : + t: #ICompletionChaining -> ICompletionChaining + + module internal Seq = + [] + type SeqComponentFactory<'T,'U> = + class + interface ISeqFactory<'T,'U> + new : unit -> SeqComponentFactory<'T,'U> + new : pipeIdx: ``PipeIdx?`` -> + SeqComponentFactory<'T,'U> + end + and ComposedFactory<'T,'U,'V> = + class + inherit SeqComponentFactory<'T,'V> + interface ISeqFactory<'T,'V> + private new : first: ISeqFactory<'T,'U> * + second: ISeqFactory<'U,'V> * + secondPipeIdx: PipeIdx -> + ComposedFactory<'T,'U,'V> + static member + Combine : first: ISeqFactory<'T,'U> -> + second: ISeqFactory<'U,'V> -> + ISeqFactory<'T,'V> + end + and ChooseFactory<'T,'U> = + class + inherit SeqComponentFactory<'T,'U> + interface ISeqFactory<'T,'U> + new : filter:('T -> 'U option) -> ChooseFactory<'T,'U> + end + and DistinctFactory<'T when 'T : equality> = + class + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> + new : unit -> DistinctFactory<'T> + end + and DistinctByFactory<'T,'Key when 'Key : equality> = + class + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> + new : keyFunction:('T -> 'Key) -> DistinctByFactory<'T,'Key> + end + and ExceptFactory<'T when 'T : equality> = + class + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> + new : itemsToExclude:seq<'T> -> ExceptFactory<'T> + end + and FilterFactory<'T> = + class + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> + new : filter:('T -> bool) -> FilterFactory<'T> + end + and IdentityFactory<'T> = + class + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> + new : unit -> IdentityFactory<'T> + static member Instance : IdentityFactory<'T> + end + and MapFactory<'T,'U> = + class + inherit SeqComponentFactory<'T,'U> + interface ISeqFactory<'T,'U> + new : map:('T -> 'U) -> MapFactory<'T,'U> + end + and Map2FirstFactory<'First,'Second,'U> = + class + inherit SeqComponentFactory<'First,'U> + interface ISeqFactory<'First,'U> + new : map:('First -> 'Second -> 'U) * + input2:IEnumerable<'Second> -> + Map2FirstFactory<'First,'Second,'U> + end + and Map2SecondFactory<'First,'Second,'U> = + class + inherit SeqComponentFactory<'Second,'U> + interface ISeqFactory<'Second,'U> + new : map:('First -> 'Second -> 'U) * + input1:IEnumerable<'First> -> + Map2SecondFactory<'First,'Second,'U> + end + and Map3Factory<'First,'Second,'Third,'U> = + class + inherit SeqComponentFactory<'First,'U> + interface ISeqFactory<'First,'U> + new : map:('First -> 'Second -> 'Third -> 'U) * + input2:IEnumerable<'Second> * + input3:IEnumerable<'Third> -> + Map3Factory<'First,'Second,'Third,'U> + end + and MapiFactory<'T,'U> = + class + inherit SeqComponentFactory<'T,'U> + interface ISeqFactory<'T,'U> + new : mapi:(int -> 'T -> 'U) -> MapiFactory<'T,'U> + end + and Mapi2Factory<'First,'Second,'U> = + class + inherit SeqComponentFactory<'First,'U> + interface ISeqFactory<'First,'U> + new : map:(int -> 'First -> 'Second -> 'U) * + input2:IEnumerable<'Second> -> + Mapi2Factory<'First,'Second,'U> + end + and PairwiseFactory<'T> = + class + inherit SeqComponentFactory<'T,('T * 'T)> + interface ISeqFactory<'T,('T * 'T)> + new : unit -> PairwiseFactory<'T> + end + and ScanFactory<'T,'State> = + class + inherit SeqComponentFactory<'T,'State> + interface ISeqFactory<'T,'State> + new : folder:('State -> 'T -> 'State) * initialState:'State -> + ScanFactory<'T,'State> + end + and SkipFactory<'T> = + class + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> + new : count:int -> SkipFactory<'T> + end + and SkipWhileFactory<'T> = + class + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> + new : predicate:('T -> bool) -> SkipWhileFactory<'T> + end + and TakeWhileFactory<'T> = + class + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> + new : predicate:('T -> bool) -> TakeWhileFactory<'T> + end + and TakeFactory<'T> = + class + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> + new : count:int -> TakeFactory<'T> + end + and TailFactory<'T> = + class + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> + new : unit -> TailFactory<'T> + end + and TruncateFactory<'T> = + class + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> + new : count:int -> TruncateFactory<'T> + end + and WindowedFactory<'T> = + class + inherit SeqComponentFactory<'T,'T []> + interface ISeqFactory<'T,'T []> + new : windowSize:int -> WindowedFactory<'T> + end + and [] SeqComponent<'T,'U> = + class + inherit Consumer<'T,'U> + interface ICompletionChaining + new : next: ICompletionChaining -> + SeqComponent<'T,'U> + abstract member + CreateFilter : filter:('T -> bool) -> SeqComponent<'T,'U> + abstract member + CreateMap : map:('S -> 'T) -> SeqComponent<'S,'U> + abstract member Skipping : unit -> bool + override + CreateFilter : filter:('T -> bool) -> SeqComponent<'T,'U> + override CreateMap : map:('S -> 'T) -> SeqComponent<'S,'U> + override Skipping : unit -> bool + end + and Choose<'T,'U,'V> = + class + inherit SeqComponent<'T,'V> + new : choose:('T -> 'U option) * next: Consumer<'U,'V> -> + Choose<'T,'U,'V> + override ProcessNext : input:'T -> bool + end + and Distinct<'T,'V when 'T : equality> = + class + inherit SeqComponent<'T,'V> + new : next: Consumer<'T,'V> -> Distinct<'T,'V> + override ProcessNext : input:'T -> bool + end + and DistinctBy<'T,'Key,'V when 'Key : equality> = + class + inherit SeqComponent<'T,'V> + new : keyFunction:('T -> 'Key) * next: Consumer<'T,'V> -> + DistinctBy<'T,'Key,'V> + override ProcessNext : input:'T -> bool + end + and Except<'T,'V when 'T : equality> = + class + inherit SeqComponent<'T,'V> + new : itemsToExclude:seq<'T> * next: Consumer<'T,'V> -> + Except<'T,'V> + override ProcessNext : input:'T -> bool + end + and Filter<'T,'V> = + class + inherit SeqComponent<'T,'V> + new : filter:('T -> bool) * next: Consumer<'T,'V> -> + Filter<'T,'V> + override CreateMap : map:('S -> 'T) -> SeqComponent<'S,'V> + override ProcessNext : input:'T -> bool + end + and FilterThenMap<'T,'U,'V> = + class + inherit SeqComponent<'T,'V> + new : filter:('T -> bool) * map:('T -> 'U) * + next: Consumer<'U,'V> -> + FilterThenMap<'T,'U,'V> + override ProcessNext : input:'T -> bool + end + and Map<'T,'U,'V> = + class + inherit SeqComponent<'T,'V> + new : map:('T -> 'U) * next: Consumer<'U,'V> -> + Map<'T,'U,'V> + override + CreateFilter : filter:('T -> bool) -> SeqComponent<'T,'V> + override ProcessNext : input:'T -> bool + end + and Map2First<'First,'Second,'U,'V> = + class + inherit SeqComponent<'First,'V> + new : map:('First -> 'Second -> 'U) * + enumerable2:IEnumerable<'Second> * + outOfBand: IOutOfBand * + next: Consumer<'U,'V> * pipeIdx:int -> + Map2First<'First,'Second,'U,'V> + override OnDispose : unit -> unit + override ProcessNext : input:'First -> bool + end + and Map2Second<'First,'Second,'U,'V> = + class + inherit SeqComponent<'Second,'V> + new : map:('First -> 'Second -> 'U) * + enumerable1:IEnumerable<'First> * + outOfBand: IOutOfBand * + next: Consumer<'U,'V> * pipeIdx:int -> + Map2Second<'First,'Second,'U,'V> + override OnDispose : unit -> unit + override ProcessNext : input:'Second -> bool + end + and Map3<'First,'Second,'Third,'U,'V> = + class + inherit SeqComponent<'First,'V> + new : map:('First -> 'Second -> 'Third -> 'U) * + enumerable2:IEnumerable<'Second> * + enumerable3:IEnumerable<'Third> * + outOfBand: IOutOfBand * + next: Consumer<'U,'V> * pipeIdx:int -> + Map3<'First,'Second,'Third,'U,'V> + override OnDispose : unit -> unit + override ProcessNext : input:'First -> bool + end + and MapThenFilter<'T,'U,'V> = + class + inherit SeqComponent<'T,'V> + new : map:('T -> 'U) * filter:('U -> bool) * + next: Consumer<'U,'V> -> + MapThenFilter<'T,'U,'V> + override ProcessNext : input:'T -> bool + end + and Mapi<'T,'U,'V> = + class + inherit SeqComponent<'T,'V> + new : mapi:(int -> 'T -> 'U) * next: Consumer<'U,'V> -> + Mapi<'T,'U,'V> + override ProcessNext : input:'T -> bool + end + and Mapi2<'First,'Second,'U,'V> = + class + inherit SeqComponent<'First,'V> + new : map:(int -> 'First -> 'Second -> 'U) * + enumerable2:IEnumerable<'Second> * + outOfBand: IOutOfBand * + next: Consumer<'U,'V> * pipeIdx:int -> + Mapi2<'First,'Second,'U,'V> + override OnDispose : unit -> unit + override ProcessNext : input:'First -> bool + end + and Pairwise<'T,'V> = + class + inherit SeqComponent<'T,'V> + new : next: Consumer<('T * 'T),'V> -> + Pairwise<'T,'V> + override ProcessNext : input:'T -> bool + end + and Scan<'T,'State,'V> = + class + inherit SeqComponent<'T,'V> + new : folder:('State -> 'T -> 'State) * initialState:'State * + next: Consumer<'State,'V> -> + Scan<'T,'State,'V> + override ProcessNext : input:'T -> bool + end + and Skip<'T,'V> = + class + inherit SeqComponent<'T,'V> + new : skipCount:int * next: Consumer<'T,'V> -> + Skip<'T,'V> + override OnComplete : PipeIdx -> unit + override ProcessNext : input:'T -> bool + override Skipping : unit -> bool + end + and SkipWhile<'T,'V> = + class + inherit SeqComponent<'T,'V> + new : predicate:('T -> bool) * next: Consumer<'T,'V> -> + SkipWhile<'T,'V> + override ProcessNext : input:'T -> bool + end + and Take<'T,'V> = + class + inherit Truncate<'T,'V> + new : takeCount:int * outOfBand: IOutOfBand * + next: Consumer<'T,'V> * pipelineIdx:int -> + Take<'T,'V> + override OnComplete : terminatingIdx: PipeIdx -> unit + end + and TakeWhile<'T,'V> = + class + inherit SeqComponent<'T,'V> + new : predicate:('T -> bool) * outOfBand: IOutOfBand * + next: Consumer<'T,'V> * pipeIdx:int -> + TakeWhile<'T,'V> + override ProcessNext : input:'T -> bool + end + and Tail<'T,'V> = + class + inherit SeqComponent<'T,'V> + new : next: Consumer<'T,'V> -> Tail<'T,'V> + override OnComplete : PipeIdx -> unit + override ProcessNext : input:'T -> bool + end + and Truncate<'T,'V> = + class + inherit SeqComponent<'T,'V> + new : truncateCount:int * outOfBand: IOutOfBand * + next: Consumer<'T,'V> * pipeIdx:int -> + Truncate<'T,'V> + override ProcessNext : input:'T -> bool + member Count : int + end + and Windowed<'T,'V> = + class + inherit SeqComponent<'T,'V> + new : windowSize:int * next: Consumer<'T [],'V> -> + Windowed<'T,'V> + override ProcessNext : input:'T -> bool + end + type SeqProcessNextStates = + | InProcess = 0 + | NotStarted = 1 + | Finished = 2 + type Result<'T> = + class + interface IOutOfBand + new : unit -> Result<'T> + member Current : 'T + member HaltedIdx : int + member SeqState : SeqProcessNextStates + member Current : 'T with set + member SeqState : SeqProcessNextStates with set + end + type SetResult<'T> = + class + inherit Consumer<'T,'T> + new : result: Result<'T> -> SetResult<'T> + override ProcessNext : input:'T -> bool + end + type OutOfBand = + class + interface IOutOfBand + new : unit -> OutOfBand + member HaltedIdx : int + end + module ForEach = begin + val enumerable : + enumerable:IEnumerable<'T> -> + outOfBand: OutOfBand -> + consumer: Consumer<'T,'U> -> unit + val array : + array:'T array -> + outOfBand: OutOfBand -> + consumer: Consumer<'T,'U> -> unit + val list : + alist:'T list -> + outOfBand: OutOfBand -> + consumer: Consumer<'T,'U> -> unit + val unfold : + generator:('S -> ('T * 'S) option) -> + state:'S -> + outOfBand: OutOfBand -> + consumer: Consumer<'T,'U> -> unit + val makeIsSkipping : + consumer: Consumer<'T,'U> -> (unit -> bool) + val init : + f:(int -> 'T) -> + terminatingIdx:int -> + outOfBand: OutOfBand -> + consumer: Consumer<'T,'U> -> unit + val execute : + f:((unit -> unit) -> 'a) -> + current: ISeqFactory<'T,'U> -> + executeOn:( OutOfBand -> Consumer<'T,'U> -> + unit) -> 'a when 'a :> Consumer<'U,'U> + end + module Enumerable = begin + type Empty<'T> = + class + interface IDisposable + interface IEnumerator + interface IEnumerator<'T> + new : unit -> Empty<'T> + end + type EmptyEnumerators<'T> = + class + new : unit -> EmptyEnumerators<'T> + static member Element : IEnumerator<'T> + end + [] + type EnumeratorBase<'T> = + class + interface IEnumerator<'T> + interface IEnumerator + interface IDisposable + new : result: Result<'T> * + seqComponent: ICompletionChaining -> + EnumeratorBase<'T> + end + and [] EnumerableBase<'T> = + class + interface ISeq<'T> + interface IEnumerable<'T> + interface IEnumerable + new : unit -> EnumerableBase<'T> + abstract member + Append : seq<'T> -> IEnumerable<'T> + override + Append : source:seq<'T> -> IEnumerable<'T> + end + and Enumerator<'T,'U> = + class + inherit EnumeratorBase<'U> + interface IDisposable + interface IEnumerator + new : source:IEnumerator<'T> * + seqComponent: Consumer<'T,'U> * + result: Result<'U> -> + Enumerator<'T,'U> + end + and Enumerable<'T,'U> = + class + inherit EnumerableBase<'U> + interface ISeq<'U> + interface IEnumerable<'U> + new : enumerable:IEnumerable<'T> * + current: ISeqFactory<'T,'U> -> + Enumerable<'T,'U> + end + and ConcatEnumerator<'T,'Collection when 'Collection :> seq<'T>> = + class + interface IDisposable + interface IEnumerator + interface IEnumerator<'T> + new : sources:seq<'Collection> -> + ConcatEnumerator<'T,'Collection> + end + and AppendEnumerable<'T> = + class + inherit EnumerableBase<'T> + interface ISeq<'T> + interface IEnumerable<'T> + new : sources:seq<'T> list -> AppendEnumerable<'T> + override + Append : source:seq<'T> -> + IEnumerable<'T> + end + and ConcatEnumerable<'T,'Collection when 'Collection :> seq<'T>> = + class + inherit EnumerableBase<'T> + interface ISeq<'T> + interface IEnumerable<'T> + new : sources:seq<'Collection> -> + ConcatEnumerable<'T,'Collection> + end + val create : + enumerable:IEnumerable<'a> -> + current: ISeqFactory<'a,'b> -> ISeq<'b> + end + module EmptyEnumerable = begin + type Enumerable<'T> = + class + inherit Enumerable.EnumerableBase<'T> + interface ISeq<'T> + interface IEnumerable<'T> + new : unit -> Enumerable<'T> + override + Append : source:seq<'T> -> IEnumerable<'T> + static member Instance : ISeq<'T> + end + end + module Array = begin + type Enumerator<'T,'U> = + class + inherit Enumerable.EnumeratorBase<'U> + interface IEnumerator + new : delayedArray:(unit -> 'T array) * + seqComponent: Consumer<'T,'U> * + result: Result<'U> -> Enumerator<'T,'U> + end + type Enumerable<'T,'U> = + class + inherit Enumerable.EnumerableBase<'U> + interface ISeq<'U> + interface IEnumerable<'U> + new : delayedArray:(unit -> 'T array) * + current: ISeqFactory<'T,'U> -> + Enumerable<'T,'U> + end + val createDelayed : + delayedArray:(unit -> 'T array) -> + current: ISeqFactory<'T,'U> -> ISeq<'U> + val create : + array:'T array -> + current: ISeqFactory<'T,'U> -> ISeq<'U> + val createDelayedId : + delayedArray:(unit -> 'T array) -> ISeq<'T> + val createId : array:'T array -> ISeq<'T> + end + module List = begin + type Enumerator<'T,'U> = + class + inherit Enumerable.EnumeratorBase<'U> + interface IEnumerator + new : alist:'T list * seqComponent: Consumer<'T,'U> * + result: Result<'U> -> Enumerator<'T,'U> + end + type Enumerable<'T,'U> = + class + inherit Enumerable.EnumerableBase<'U> + interface ISeq<'U> + interface IEnumerable<'U> + new : alist:'T list * current: ISeqFactory<'T,'U> -> + Enumerable<'T,'U> + end + val create : + alist:'a list -> + current: ISeqFactory<'a,'b> -> ISeq<'b> + end + module Unfold = begin + type Enumerator<'T,'U,'State> = + class + inherit Enumerable.EnumeratorBase<'U> + interface IEnumerator + new : generator:('State -> ('T * 'State) option) * state:'State * + seqComponent: Consumer<'T,'U> * + result: Result<'U> -> + Enumerator<'T,'U,'State> + end + type Enumerable<'T,'U,'GeneratorState> = + class + inherit Enumerable.EnumerableBase<'U> + interface ISeq<'U> + interface IEnumerable<'U> + new : generator:('GeneratorState -> ('T * 'GeneratorState) option) * + state:'GeneratorState * current: ISeqFactory<'T,'U> -> + Enumerable<'T,'U,'GeneratorState> + end + end + module Init = begin + val getTerminatingIdx : count:Nullable -> int + type Enumerator<'T,'U> = + class + inherit Enumerable.EnumeratorBase<'U> + interface IEnumerator + new : count:Nullable * f:(int -> 'T) * + seqComponent: Consumer<'T,'U> * + result: Result<'U> -> Enumerator<'T,'U> + end + type Enumerable<'T,'U> = + class + inherit Enumerable.EnumerableBase<'U> + interface ISeq<'U> + interface IEnumerable<'U> + new : count:Nullable * f:(int -> 'T) * + current: ISeqFactory<'T,'U> -> + Enumerable<'T,'U> + end + val upto : + lastOption:int option -> + f:(int -> 'U) -> IEnumerator<'U> + type EnumerableDecider<'T> = + class + inherit Enumerable.EnumerableBase<'T> + interface ISeq<'T> + interface IEnumerable<'T> + new : count:Nullable * f:(int -> 'T) -> + EnumerableDecider<'T> + end + end + [] + val toComposer : source:seq<'T> -> ISeq<'T> + val inline foreach : + f:((unit -> unit) -> 'a) -> source: ISeq<'b> -> 'a + when 'a :> Consumer<'b,'b> + val inline compose : + factory: ISeqFactory<'T,'a> -> + source: ISeq<'T> -> ISeq<'a> + [] + val empty<'T> : ISeq<'T> + [] + val unfold : + generator:('State -> ('T * 'State) option) -> + state:'State -> ISeq<'T> + [] + val initInfinite : f:(int -> 'T) -> ISeq<'T> + [] + val init : count:int -> f:(int -> 'T) -> ISeq<'T> + [] + val iter : f:('T -> unit) -> source: ISeq<'T> -> unit + [] + val tryItem : i:int -> source: ISeq<'T> -> 'T option + [] + val iteri : f:(int -> 'T -> unit) -> source: ISeq<'T> -> unit + [] + val exists : f:('T -> bool) -> source: ISeq<'T> -> bool + [] + val inline contains : + element:'T -> source: ISeq<'T> -> bool when 'T : equality + [] + val forall : f:('T -> bool) -> source: ISeq<'T> -> bool + [] + val filter : + f:('T -> bool) -> source: ISeq<'T> -> ISeq<'T> + [] + val map : + f:('T -> 'U) -> source: ISeq<'T> -> ISeq<'U> + [] + val mapi : + f:(int -> 'a -> 'b) -> + source: ISeq<'a> -> ISeq<'b> + [] + val choose : + f:('a -> 'b option) -> + source: ISeq<'a> -> ISeq<'b> + [] + val indexed : source: ISeq<'a> -> ISeq + [] + val tryPick : + f:('T -> 'U option) -> source: ISeq<'T> -> Option<'U> + [] + val tryFind : f:('T -> bool) -> source: ISeq<'T> -> Option<'T> + diff --git a/src/fsharp/FSharp.Core/seqcore.fs b/src/fsharp/FSharp.Core/seqcore.fs new file mode 100644 index 00000000000..657c58d1681 --- /dev/null +++ b/src/fsharp/FSharp.Core/seqcore.fs @@ -0,0 +1,405 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.FSharp.Collections + #nowarn "52" // The value has been copied to ensure the original is not mutated by this operation + + open System + open System.Diagnostics + open System.Collections + open System.Collections.Generic + open Microsoft.FSharp.Core + open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators + open Microsoft.FSharp.Core.Operators + open Microsoft.FSharp.Control + open Microsoft.FSharp.Collections + + module internal IEnumerator = + + let noReset() = raise (new System.NotSupportedException(SR.GetString(SR.resetNotSupported))) + let notStarted() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationNotStarted))) + let alreadyFinished() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationAlreadyFinished))) + let check started = if not started then notStarted() + let dispose (r : System.IDisposable) = r.Dispose() + + let cast (e : IEnumerator) : IEnumerator<'T> = + { new IEnumerator<'T> with + member x.Current = unbox<'T> e.Current + interface IEnumerator with + member x.Current = unbox<'T> e.Current :> obj + member x.MoveNext() = e.MoveNext() + member x.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = + match e with + | :? System.IDisposable as e -> e.Dispose() + | _ -> () } + + /// A concrete implementation of an enumerator that returns no values + [] + type EmptyEnumerator<'T>() = + let mutable started = false + interface IEnumerator<'T> with + member x.Current = + check started + (alreadyFinished() : 'T) + + interface System.Collections.IEnumerator with + member x.Current = + check started + (alreadyFinished() : obj) + member x.MoveNext() = + if not started then started <- true + false + member x.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = () + + let Empty<'T> () = (new EmptyEnumerator<'T>() :> IEnumerator<'T>) + [] + type EmptyEnumerable<'T> = + | EmptyEnumerable + interface IEnumerable<'T> with + member x.GetEnumerator() = Empty<'T>() + interface IEnumerable with + member x.GetEnumerator() = (Empty<'T>() :> IEnumerator) + + let readAndClear r = + lock r (fun () -> match !r with None -> None | Some _ as res -> r := None; res) + + let generateWhileSome openf compute closef : IEnumerator<'U> = + let started = ref false + let curr = ref None + let state = ref (Some(openf())) + let getCurr() = + check !started + match !curr with None -> alreadyFinished() | Some x -> x + let start() = if not !started then (started := true) + + let dispose() = readAndClear state |> Option.iter closef + let finish() = (try dispose() finally curr := None) + { new IEnumerator<'U> with + member x.Current = getCurr() + interface IEnumerator with + member x.Current = box (getCurr()) + member x.MoveNext() = + start() + match !state with + | None -> false (* we started, then reached the end, then got another MoveNext *) + | Some s -> + match (try compute s with e -> finish(); reraise()) with + | None -> finish(); false + | Some _ as x -> curr := x; true + + member x.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = dispose() } + + [] + type Singleton<'T>(v:'T) = + let mutable started = false + interface IEnumerator<'T> with + member x.Current = v + interface IEnumerator with + member x.Current = box v + member x.MoveNext() = if started then false else (started <- true; true) + member x.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = () + + let Singleton x = (new Singleton<'T>(x) :> IEnumerator<'T>) + + let EnumerateThenFinally f (e : IEnumerator<'T>) = + { new IEnumerator<'T> with + member x.Current = e.Current + interface IEnumerator with + member x.Current = (e :> IEnumerator).Current + member x.MoveNext() = e.MoveNext() + member x.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = + try + e.Dispose() + finally + f() + } + + let inline checkNonNull argName arg = + match box arg with + | null -> nullArg argName + | _ -> () + + let mkSeq f = + { new IEnumerable<'U> with + member x.GetEnumerator() = f() + interface IEnumerable with + member x.GetEnumerator() = (f() :> IEnumerator) + } + +namespace Microsoft.FSharp.Core.CompilerServices + + open System + open System.Diagnostics + open Microsoft.FSharp.Core + open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators + open Microsoft.FSharp.Core.Operators + open Microsoft.FSharp.Control + open Microsoft.FSharp.Collections + open Microsoft.FSharp.Primitives.Basics + open System.Collections + open System.Collections.Generic + open Microsoft.FSharp.Collections.IEnumerator + + module RuntimeHelpers = + + [] + type internal StructBox<'T when 'T : equality>(value:'T) = + member x.Value = value + static member Comparer = + let gcomparer = HashIdentity.Structural<'T> + { new IEqualityComparer> with + member __.GetHashCode(v) = gcomparer.GetHashCode(v.Value) + member __.Equals(v1,v2) = gcomparer.Equals(v1.Value,v2.Value) } + + let Generate openf compute closef = + mkSeq (fun () -> IEnumerator.generateWhileSome openf compute closef) + + let GenerateUsing (openf : unit -> ('U :> System.IDisposable)) compute = + Generate openf compute (fun (s:'U) -> s.Dispose()) + + let EnumerateFromFunctions opener moveNext current = + Generate + opener + (fun x -> if moveNext x then Some(current x) else None) + (fun x -> match box(x) with :? System.IDisposable as id -> id.Dispose() | _ -> ()) + + // A family of enumerators that can have additional 'finally' actions added to the enumerator through + // the use of mutation. This is used to 'push' the disposal action for a 'use' into the next enumerator. + // For example, + // seq { use x = ... + // while ... } + // results in the 'while' loop giving an adjustable enumerator. This is then adjusted by adding the disposal action + // from the 'use' into the enumerator. This means that we avoid constructing a two-deep enumerator chain in this + // common case. + type IFinallyEnumerator = + abstract AppendFinallyAction : (unit -> unit) -> unit + + /// A concrete implementation of IEnumerable that adds the given compensation to the "Dispose" chain of any + /// enumerators returned by the enumerable. + [] + type FinallyEnumerable<'T>(compensation: unit -> unit, restf: unit -> seq<'T>) = + interface IEnumerable<'T> with + member x.GetEnumerator() = + try + let ie = restf().GetEnumerator() + match ie with + | :? IFinallyEnumerator as a -> + a.AppendFinallyAction(compensation) + ie + | _ -> + IEnumerator.EnumerateThenFinally compensation ie + with e -> + compensation() + reraise() + interface IEnumerable with + member x.GetEnumerator() = ((x :> IEnumerable<'T>).GetEnumerator() :> IEnumerator) + + /// An optimized object for concatenating a sequence of enumerables + [] + type ConcatEnumerator<'T,'U when 'U :> seq<'T>>(sources: seq<'U>) = + let mutable outerEnum = sources.GetEnumerator() + let mutable currInnerEnum = IEnumerator.Empty() + + let mutable started = false + let mutable finished = false + let mutable compensations = [] + + [] // false = unchecked + val mutable private currElement : 'T + + member x.Finish() = + finished <- true + try + match currInnerEnum with + | null -> () + | _ -> + try + currInnerEnum.Dispose() + finally + currInnerEnum <- null + finally + try + match outerEnum with + | null -> () + | _ -> + try + outerEnum.Dispose() + finally + outerEnum <- null + finally + let rec iter comps = + match comps with + | [] -> () + | h::t -> + try h() finally iter t + try + compensations |> List.rev |> iter + finally + compensations <- [] + + member x.GetCurrent() = + IEnumerator.check started + if finished then IEnumerator.alreadyFinished() else x.currElement + + interface IFinallyEnumerator with + member x.AppendFinallyAction(f) = + compensations <- f :: compensations + + interface IEnumerator<'T> with + member x.Current = x.GetCurrent() + + interface IEnumerator with + member x.Current = box (x.GetCurrent()) + + member x.MoveNext() = + if not started then (started <- true) + if finished then false + else + let rec takeInner () = + // check the inner list + if currInnerEnum.MoveNext() then + x.currElement <- currInnerEnum.Current + true + else + // check the outer list + let rec takeOuter() = + if outerEnum.MoveNext() then + let ie = outerEnum.Current + // Optimization to detect the statically-allocated empty IEnumerables + match box ie with + | :? EmptyEnumerable<'T> -> + // This one is empty, just skip, don't call GetEnumerator, try again + takeOuter() + | _ -> + // OK, this one may not be empty. + // Don't forget to dispose of the enumerator for the inner list now we're done with it + currInnerEnum.Dispose() + currInnerEnum <- ie.GetEnumerator() + takeInner () + else + // We're done + x.Finish() + false + takeOuter() + takeInner () + + member x.Reset() = IEnumerator.noReset() + + interface System.IDisposable with + member x.Dispose() = + if not finished then + x.Finish() + + let EnumerateUsing (resource : 'T :> System.IDisposable) (rest: 'T -> #seq<'U>) = + (FinallyEnumerable((fun () -> match box resource with null -> () | _ -> resource.Dispose()), + (fun () -> rest resource :> seq<_>)) :> seq<_>) + + let mkConcatSeq (sources: seq<'U :> seq<'T>>) = + mkSeq (fun () -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>) + + let EnumerateWhile (g : unit -> bool) (b: seq<'T>) : seq<'T> = + let started = ref false + let curr = ref None + let getCurr() = + IEnumerator.check !started + match !curr with None -> IEnumerator.alreadyFinished() | Some x -> x + let start() = if not !started then (started := true) + + let finish() = (curr := None) + mkConcatSeq + (mkSeq (fun () -> + { new IEnumerator<_> with + member x.Current = getCurr() + interface IEnumerator with + member x.Current = box (getCurr()) + member x.MoveNext() = + start() + let keepGoing = (try g() with e -> finish (); reraise ()) in + if keepGoing then + curr := Some(b); true + else + finish(); false + member x.Reset() = IEnumerator.noReset() + interface System.IDisposable with + member x.Dispose() = () })) + + let EnumerateThenFinally (rest : seq<'T>) (compensation : unit -> unit) = + (FinallyEnumerable(compensation, (fun () -> rest)) :> seq<_>) + + let CreateEvent (add : 'Delegate -> unit) (remove : 'Delegate -> unit) (create : (obj -> 'Args -> unit) -> 'Delegate ) :IEvent<'Delegate,'Args> = + // Note, we implement each interface explicitly: this works around a bug in the CLR + // implementation on CompactFramework 3.7, used on Windows Phone 7 + { new obj() with + member x.ToString() = "" + interface IEvent<'Delegate,'Args> + interface IDelegateEvent<'Delegate> with + member x.AddHandler(h) = add h + member x.RemoveHandler(h) = remove h + interface System.IObservable<'Args> with + member x.Subscribe(r:IObserver<'Args>) = + let h = create (fun _ args -> r.OnNext(args)) + add h + { new System.IDisposable with + member x.Dispose() = remove h } } + + + [] + type GeneratedSequenceBase<'T>() = + let mutable redirectTo : GeneratedSequenceBase<'T> = Unchecked.defaultof<_> + let mutable redirect : bool = false + + abstract GetFreshEnumerator : unit -> IEnumerator<'T> + abstract GenerateNext : next:byref> -> int // 0 = Stop, 1 = Yield, 2 = Goto + abstract Close: unit -> unit + abstract CheckClose: bool + abstract LastGenerated : 'T + + //[] + member x.MoveNextImpl() = + let active = + if redirect then redirectTo + else x + let mutable target = null + match active.GenerateNext(&target) with + | 1 -> + true + | 2 -> + match target.GetEnumerator() with + | :? GeneratedSequenceBase<'T> as g when not active.CheckClose -> + redirectTo <- g + | e -> + redirectTo <- + { new GeneratedSequenceBase<'T>() with + member x.GetFreshEnumerator() = e + member x.GenerateNext(_) = if e.MoveNext() then 1 else 0 + member x.Close() = try e.Dispose() finally active.Close() + member x.CheckClose = true + member x.LastGenerated = e.Current } + redirect <- true + x.MoveNextImpl() + | _ (* 0 *) -> + false + + interface IEnumerable<'T> with + member x.GetEnumerator() = x.GetFreshEnumerator() + interface IEnumerable with + member x.GetEnumerator() = (x.GetFreshEnumerator() :> IEnumerator) + interface IEnumerator<'T> with + member x.Current = if redirect then redirectTo.LastGenerated else x.LastGenerated + member x.Dispose() = if redirect then redirectTo.Close() else x.Close() + interface IEnumerator with + member x.Current = box (if redirect then redirectTo.LastGenerated else x.LastGenerated) + + //[] + member x.MoveNext() = x.MoveNextImpl() + + member x.Reset() = raise <| new System.NotSupportedException() \ No newline at end of file diff --git a/src/fsharp/FSharp.Core/seqcore.fsi b/src/fsharp/FSharp.Core/seqcore.fsi new file mode 100644 index 00000000000..8c915c921cb --- /dev/null +++ b/src/fsharp/FSharp.Core/seqcore.fsi @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.FSharp.Collections + open System + open System.Collections + open System.Collections.Generic + open Microsoft.FSharp.Core + open Microsoft.FSharp.Collections + module internal IEnumerator = + val noReset : unit -> 'a + val notStarted : unit -> 'a + val alreadyFinished : unit -> 'a + val check : started:bool -> unit + val dispose : r:System.IDisposable -> unit + val cast : + e:System.Collections.IEnumerator -> + System.Collections.Generic.IEnumerator<'T> + [] + type EmptyEnumerator<'T> = + class + interface System.IDisposable + interface System.Collections.IEnumerator + interface System.Collections.Generic.IEnumerator<'T> + new : unit -> EmptyEnumerator<'T> + end + val Empty : unit -> System.Collections.Generic.IEnumerator<'T> + [] + type EmptyEnumerable<'T> = + | EmptyEnumerable + with + interface System.Collections.IEnumerable + interface System.Collections.Generic.IEnumerable<'T> + end + + val readAndClear : r:'a option ref -> 'a option + val generateWhileSome : + openf:(unit -> 'a) -> + compute:('a -> 'U option) -> + closef:('a -> unit) -> System.Collections.Generic.IEnumerator<'U> + [] + type Singleton<'T> = + class + interface System.IDisposable + interface System.Collections.IEnumerator + interface System.Collections.Generic.IEnumerator<'T> + new : v:'T -> Singleton<'T> + end + val Singleton : x:'T -> System.Collections.Generic.IEnumerator<'T> + val EnumerateThenFinally : + f:(unit -> unit) -> + e:System.Collections.Generic.IEnumerator<'T> -> + System.Collections.Generic.IEnumerator<'T> + val inline checkNonNull : argName:string -> arg:'a -> unit + val mkSeq : + f:(unit -> System.Collections.Generic.IEnumerator<'U>) -> + System.Collections.Generic.IEnumerable<'U> + +namespace Microsoft.FSharp.Core.CompilerServices + + open System + open System.Collections + open System.Collections.Generic + open Microsoft.FSharp.Core + open Microsoft.FSharp.Collections + + + [] + /// A group of functions used as part of the compiled representation of F# sequence expressions. + module RuntimeHelpers = + + [] + type internal StructBox<'T when 'T : equality> = + new : value:'T -> StructBox<'T> + member Value : 'T + static member Comparer : IEqualityComparer> + + /// The F# compiler emits calls to this function to + /// implement the while operator for F# sequence expressions. + /// + /// A function that indicates whether iteration should continue. + /// The input sequence. + /// + /// The result sequence. + val EnumerateWhile : guard:(unit -> bool) -> source:seq<'T> -> seq<'T> + + /// The F# compiler emits calls to this function to + /// implement the try/finally operator for F# sequence expressions. + /// + /// The input sequence. + /// A computation to be included in an enumerator's Dispose method. + /// + /// The result sequence. + val EnumerateThenFinally : source:seq<'T> -> compensation:(unit -> unit) -> seq<'T> + + /// The F# compiler emits calls to this function to implement the compiler-intrinsic + /// conversions from untyped System.Collections.IEnumerable sequences to typed sequences. + /// + /// An initializer function. + /// A function to iterate and test if end of sequence is reached. + /// A function to retrieve the current element. + /// + /// The resulting typed sequence. + val EnumerateFromFunctions: create:(unit -> 'T) -> moveNext:('T -> bool) -> current:('T -> 'U) -> seq<'U> + + /// The F# compiler emits calls to this function to implement the use operator for F# sequence + /// expressions. + /// + /// The resource to be used and disposed. + /// The input sequence. + /// + /// The result sequence. + val EnumerateUsing : resource:'T -> source:('T -> 'Collection) -> seq<'U> when 'T :> IDisposable and 'Collection :> seq<'U> + + /// Creates an anonymous event with the given handlers. + /// + /// A function to handle adding a delegate for the event to trigger. + /// A function to handle removing a delegate that the event triggers. + /// A function to produce the delegate type the event can trigger. + /// + /// The initialized event. + val CreateEvent : addHandler : ('Delegate -> unit) -> removeHandler : ('Delegate -> unit) -> createHandler : ((obj -> 'Args -> unit) -> 'Delegate) -> Microsoft.FSharp.Control.IEvent<'Delegate,'Args> + + [] + /// The F# compiler emits implementations of this type for compiled sequence expressions. + type GeneratedSequenceBase<'T> = + /// The F# compiler emits implementations of this type for compiled sequence expressions. + /// + /// A new sequence generator for the expression. + new : unit -> GeneratedSequenceBase<'T> + /// The F# compiler emits implementations of this type for compiled sequence expressions. + /// + /// A new enumerator for the sequence. + abstract GetFreshEnumerator : unit -> IEnumerator<'T> + /// The F# compiler emits implementations of this type for compiled sequence expressions. + /// + /// A reference to the sequence. + /// + /// A 0, 1, and 2 respectively indicate Stop, Yield, and Goto conditions for the sequence generator. + abstract GenerateNext : result:byref> -> int + /// The F# compiler emits implementations of this type for compiled sequence expressions. + abstract Close: unit -> unit + /// The F# compiler emits implementations of this type for compiled sequence expressions. + abstract CheckClose: bool + /// The F# compiler emits implementations of this type for compiled sequence expressions. + abstract LastGenerated : 'T + interface IEnumerable<'T> + interface IEnumerable + interface IEnumerator<'T> + interface IEnumerator + From 302402b05398e1305e03bdbedd3e94c08f097ee7 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sat, 5 Nov 2016 00:59:20 +0100 Subject: [PATCH 31/59] Remove Helper from signature file Probably shouldn't be exposed in that manor in the first place, but secondly they caused a error in ci_part1. Used this as a chance to rename the module as well. Update LinqAggreagates output Due to the change in the inline functions within Seq (i.e. sum etc.) there are significant changes within this file. Modified item/tryItem to use skip Unit tests check that the item call object the lazy nature of the Seq.init Patch up the surface area. Still subject to change. Starting the exposure of the inlinable Composer - Still hidden via internal module - simplified PipeIdx, no need for optional now - Made ISeqFactory an abstract class instead of interface so as not to require a stub implementation of PipeIdx in every object expression (or alternatively if the abstract class was used with the interface, then explicit declaration of the interface as well) - filter and map changed to inline versions Fix incorrect pipeIdx Hack to stop tail calls on ICompletionChaining passing a reference as an argument in a funciton stops the F# compiler from outputting a tail instruction for that function. None of these functions will be significantly deep as to warrant the need for a tail call. mapi to inline version - added a mapi_adapt version for non-inlined Removed old choose function localizing upto This is retained for compatibility cleaning up SeqComposer.Helpers - better comments - consistent casing Seq.map3 Seq.mapi2 Simplified map2 - removing the check of both types Seq.unfold Added an IdentityFactory Identity can be used to wrap basic containers into SeqComposer compatible types, but can safely be removed when composing the components. --- .../SurfaceArea.coreclr.fs | 58 + .../SurfaceArea.net40.fs | 58 + .../SurfaceArea.portable259.fs | 58 + .../SurfaceArea.portable47.fs | 58 + .../SurfaceArea.portable7.fs | 58 + .../SurfaceArea.portable78.fs | 58 + src/fsharp/FSharp.Core/seq.fs | 1445 +++++++++++++++- src/fsharp/FSharp.Core/seqcomposer.fs | 560 +++--- src/fsharp/FSharp.Core/seqcomposer.fsi | 260 +-- .../Linq101Aggregates01.il.netfx4.bsl | 1518 +++++++++-------- .../fsharpqa/Source/Misc/LongSourceFile01.fs | 58 + 11 files changed, 2940 insertions(+), 1249 deletions(-) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs index cd7c9087a50..8b8c19eb713 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs @@ -207,6 +207,63 @@ Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.ICom Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]() Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString() Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void .ctor() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: TResult Value +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void .ctor(TResult) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand: Void StopFurtherProcessing(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Consumer`2 Create[V](IOutOfBand, System.Nullable`1[System.Int32], Consumer`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 PipeIdx +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 get_PipeIdx() +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: ISeq`1 Compose[TResult](ISeqFactory`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: a ForEach[a](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit],a]) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Void .ctor(a, b) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Void .ctor(a, b, c) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: c _3 +Microsoft.FSharp.Collections.ComposerModule+Core: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c] +Microsoft.FSharp.Collections.ComposerModule+Core: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule: Microsoft.FSharp.Collections.ComposerModule+Core +Microsoft.FSharp.Collections.ComposerModule: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule: System.Type GetType() Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Boolean Equals(System.Object) Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Cons Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Empty @@ -432,6 +489,7 @@ Microsoft.FSharp.Collections.SeqModule: Boolean Exists[T](Microsoft.FSharp.Core. Microsoft.FSharp.Collections.SeqModule: Boolean ForAll2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,System.Boolean]], System.Collections.Generic.IEnumerable`1[T1], System.Collections.Generic.IEnumerable`1[T2]) Microsoft.FSharp.Collections.SeqModule: Boolean ForAll[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Boolean IsEmpty[T](System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: ISeq`1 ToComposer[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 CompareWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], System.Collections.Generic.IEnumerable`1[T], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 FindIndexBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 FindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs index 0fdcc27abea..f446ac887cc 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs @@ -194,6 +194,63 @@ Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.ICom Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]() Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString() Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void .ctor() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: TResult Value +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void .ctor(TResult) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand: Void StopFurtherProcessing(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Consumer`2 Create[V](IOutOfBand, System.Nullable`1[System.Int32], Consumer`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 PipeIdx +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 get_PipeIdx() +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: ISeq`1 Compose[TResult](ISeqFactory`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: a ForEach[a](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit],a]) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Void .ctor(a, b) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Void .ctor(a, b, c) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: c _3 +Microsoft.FSharp.Collections.ComposerModule+Core: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c] +Microsoft.FSharp.Collections.ComposerModule+Core: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule: Microsoft.FSharp.Collections.ComposerModule+Core +Microsoft.FSharp.Collections.ComposerModule: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule: System.Type GetType() Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Boolean Equals(System.Object) Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Cons Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Empty @@ -419,6 +476,7 @@ Microsoft.FSharp.Collections.SeqModule: Boolean Exists[T](Microsoft.FSharp.Core. Microsoft.FSharp.Collections.SeqModule: Boolean ForAll2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,System.Boolean]], System.Collections.Generic.IEnumerable`1[T1], System.Collections.Generic.IEnumerable`1[T2]) Microsoft.FSharp.Collections.SeqModule: Boolean ForAll[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Boolean IsEmpty[T](System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: ISeq`1 ToComposer[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 CompareWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], System.Collections.Generic.IEnumerable`1[T], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 FindIndexBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 FindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs index cf8156e3fc8..35ea8abf8a2 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs @@ -181,6 +181,63 @@ Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.ICom Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]() Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString() Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void .ctor() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: TResult Value +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void .ctor(TResult) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand: Void StopFurtherProcessing(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Consumer`2 Create[V](IOutOfBand, System.Nullable`1[System.Int32], Consumer`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 PipeIdx +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 get_PipeIdx() +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: ISeq`1 Compose[TResult](ISeqFactory`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: a ForEach[a](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit],a]) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Void .ctor(a, b) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Void .ctor(a, b, c) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: c _3 +Microsoft.FSharp.Collections.ComposerModule+Core: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c] +Microsoft.FSharp.Collections.ComposerModule+Core: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule: Microsoft.FSharp.Collections.ComposerModule+Core +Microsoft.FSharp.Collections.ComposerModule: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule: System.Type GetType() Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Boolean Equals(System.Object) Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Cons Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Empty @@ -406,6 +463,7 @@ Microsoft.FSharp.Collections.SeqModule: Boolean Exists[T](Microsoft.FSharp.Core. Microsoft.FSharp.Collections.SeqModule: Boolean ForAll2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,System.Boolean]], System.Collections.Generic.IEnumerable`1[T1], System.Collections.Generic.IEnumerable`1[T2]) Microsoft.FSharp.Collections.SeqModule: Boolean ForAll[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Boolean IsEmpty[T](System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: ISeq`1 ToComposer[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 CompareWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], System.Collections.Generic.IEnumerable`1[T], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 FindIndexBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 FindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs index 9c63e5a4931..c16bd7d1b49 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs @@ -178,6 +178,63 @@ Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.ICom Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]() Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString() Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void .ctor() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: TResult Value +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void .ctor(TResult) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand: Void StopFurtherProcessing(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Consumer`2 Create[V](IOutOfBand, System.Nullable`1[System.Int32], Consumer`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 PipeIdx +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 get_PipeIdx() +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: ISeq`1 Compose[TResult](ISeqFactory`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: a ForEach[a](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit],a]) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Void .ctor(a, b) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Void .ctor(a, b, c) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: c _3 +Microsoft.FSharp.Collections.ComposerModule+Core: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c] +Microsoft.FSharp.Collections.ComposerModule+Core: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule: Microsoft.FSharp.Collections.ComposerModule+Core +Microsoft.FSharp.Collections.ComposerModule: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule: System.Type GetType() Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Boolean Equals(System.Object) Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Cons Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Empty @@ -403,6 +460,7 @@ Microsoft.FSharp.Collections.SeqModule: Boolean Exists[T](Microsoft.FSharp.Core. Microsoft.FSharp.Collections.SeqModule: Boolean ForAll2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,System.Boolean]], System.Collections.Generic.IEnumerable`1[T1], System.Collections.Generic.IEnumerable`1[T2]) Microsoft.FSharp.Collections.SeqModule: Boolean ForAll[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Boolean IsEmpty[T](System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: ISeq`1 ToComposer[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 CompareWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], System.Collections.Generic.IEnumerable`1[T], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 FindIndexBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 FindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs index 7c003fea400..1de212c21f0 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs @@ -194,6 +194,63 @@ Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.ICom Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]() Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString() Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void .ctor() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: TResult Value +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void .ctor(TResult) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand: Void StopFurtherProcessing(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Consumer`2 Create[V](IOutOfBand, System.Nullable`1[System.Int32], Consumer`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 PipeIdx +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 get_PipeIdx() +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: ISeq`1 Compose[TResult](ISeqFactory`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: a ForEach[a](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit],a]) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Void .ctor(a, b) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Void .ctor(a, b, c) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: c _3 +Microsoft.FSharp.Collections.ComposerModule+Core: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c] +Microsoft.FSharp.Collections.ComposerModule+Core: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule: Microsoft.FSharp.Collections.ComposerModule+Core +Microsoft.FSharp.Collections.ComposerModule: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule: System.Type GetType() Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Boolean Equals(System.Object) Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Cons Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Empty @@ -419,6 +476,7 @@ Microsoft.FSharp.Collections.SeqModule: Boolean Exists[T](Microsoft.FSharp.Core. Microsoft.FSharp.Collections.SeqModule: Boolean ForAll2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,System.Boolean]], System.Collections.Generic.IEnumerable`1[T1], System.Collections.Generic.IEnumerable`1[T2]) Microsoft.FSharp.Collections.SeqModule: Boolean ForAll[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Boolean IsEmpty[T](System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: ISeq`1 ToComposer[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 CompareWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], System.Collections.Generic.IEnumerable`1[T], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 FindIndexBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 FindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs index 4f1d01c64b6..f4f4479b4ce 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs @@ -181,6 +181,63 @@ Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.ICom Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]() Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString() Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void .ctor() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: TResult Value +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void .ctor(TResult) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand: Void StopFurtherProcessing(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Consumer`2 Create[V](IOutOfBand, System.Nullable`1[System.Int32], Consumer`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 PipeIdx +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 get_PipeIdx() +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: ISeq`1 Compose[TResult](ISeqFactory`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: a ForEach[a](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit],a]) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Void .ctor(a, b) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Void .ctor(a, b, c) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: c _3 +Microsoft.FSharp.Collections.ComposerModule+Core: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c] +Microsoft.FSharp.Collections.ComposerModule+Core: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule: Microsoft.FSharp.Collections.ComposerModule+Core +Microsoft.FSharp.Collections.ComposerModule: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule: System.Type GetType() Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Boolean Equals(System.Object) Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Cons Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Empty @@ -406,6 +463,7 @@ Microsoft.FSharp.Collections.SeqModule: Boolean Exists[T](Microsoft.FSharp.Core. Microsoft.FSharp.Collections.SeqModule: Boolean ForAll2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,System.Boolean]], System.Collections.Generic.IEnumerable`1[T1], System.Collections.Generic.IEnumerable`1[T2]) Microsoft.FSharp.Collections.SeqModule: Boolean ForAll[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Boolean IsEmpty[T](System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: ISeq`1 ToComposer[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 CompareWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], System.Collections.Generic.IEnumerable`1[T], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 FindIndexBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 FindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 8d9686b9431..9e8611ff507 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -1,5 +1,448 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +namespace Microsoft.FSharp.Collections + + open System + open System.Diagnostics + open System.Collections + open System.Collections.Generic + open Microsoft.FSharp.Core + open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators + open Microsoft.FSharp.Core.Operators + open Microsoft.FSharp.Control + open Microsoft.FSharp.Collections + + module IEnumerator = + + let noReset() = raise (new System.NotSupportedException(SR.GetString(SR.resetNotSupported))) + let notStarted() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationNotStarted))) + let alreadyFinished() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationAlreadyFinished))) + let check started = if not started then notStarted() + let dispose (r : System.IDisposable) = r.Dispose() + + let cast (e : IEnumerator) : IEnumerator<'T> = + { new IEnumerator<'T> with + member x.Current = unbox<'T> e.Current + interface IEnumerator with + member x.Current = unbox<'T> e.Current :> obj + member x.MoveNext() = e.MoveNext() + member x.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = + match e with + | :? System.IDisposable as e -> e.Dispose() + | _ -> () } + + /// A concrete implementation of an enumerator that returns no values + [] + type EmptyEnumerator<'T>() = + let mutable started = false + interface IEnumerator<'T> with + member x.Current = + check started + (alreadyFinished() : 'T) + + interface System.Collections.IEnumerator with + member x.Current = + check started + (alreadyFinished() : obj) + member x.MoveNext() = + if not started then started <- true + false + member x.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = () + + let Empty<'T> () = (new EmptyEnumerator<'T>() :> IEnumerator<'T>) + + let rec tryItem index (e : IEnumerator<'T>) = + if not (e.MoveNext()) then None + elif index = 0 then Some(e.Current) + else tryItem (index-1) e + + let rec nth index (e : IEnumerator<'T>) = + if not (e.MoveNext()) then + let shortBy = index + 1 + invalidArgFmt "index" + "{0}\nseq was short by {1} {2}" + [|SR.GetString SR.notEnoughElements; shortBy; (if shortBy = 1 then "element" else "elements")|] + if index = 0 then e.Current + else nth (index-1) e + + let readAndClear r = + lock r (fun () -> match !r with None -> None | Some _ as res -> r := None; res) + + let generateWhileSome openf compute closef : IEnumerator<'U> = + let started = ref false + let curr = ref None + let state = ref (Some(openf())) + let getCurr() = + check !started + match !curr with None -> alreadyFinished() | Some x -> x + let start() = if not !started then (started := true) + + let dispose() = readAndClear state |> Option.iter closef + let finish() = (try dispose() finally curr := None) + { new IEnumerator<'U> with + member x.Current = getCurr() + interface IEnumerator with + member x.Current = box (getCurr()) + member x.MoveNext() = + start() + match !state with + | None -> false (* we started, then reached the end, then got another MoveNext *) + | Some s -> + match (try compute s with e -> finish(); reraise()) with + | None -> finish(); false + | Some _ as x -> curr := x; true + + member x.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = dispose() } + + [] + type ArrayEnumerator<'T>(arr: 'T array) = + let mutable curr = -1 + let mutable len = arr.Length + member x.Get() = + if curr >= 0 then + if curr >= len then alreadyFinished() + else arr.[curr] + else + notStarted() + interface IEnumerator<'T> with + member x.Current = x.Get() + interface System.Collections.IEnumerator with + member x.MoveNext() = + if curr >= len then false + else + curr <- curr + 1 + (curr < len) + member x.Current = box(x.Get()) + member x.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = () + + let ofArray arr = (new ArrayEnumerator<'T>(arr) :> IEnumerator<'T>) + + [] + type Singleton<'T>(v:'T) = + let mutable started = false + interface IEnumerator<'T> with + member x.Current = v + interface IEnumerator with + member x.Current = box v + member x.MoveNext() = if started then false else (started <- true; true) + member x.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = () + + let Singleton x = (new Singleton<'T>(x) :> IEnumerator<'T>) + + let EnumerateThenFinally f (e : IEnumerator<'T>) = + { new IEnumerator<'T> with + member x.Current = e.Current + interface IEnumerator with + member x.Current = (e :> IEnumerator).Current + member x.MoveNext() = e.MoveNext() + member x.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = + try + e.Dispose() + finally + f() + } + + +namespace Microsoft.FSharp.Core.CompilerServices + + open System + open System.Diagnostics + open Microsoft.FSharp.Core + open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators + open Microsoft.FSharp.Core.Operators + open Microsoft.FSharp.Control + open Microsoft.FSharp.Collections + open Microsoft.FSharp.Primitives.Basics + open System.Collections + open System.Collections.Generic + + module RuntimeHelpers = + + [] + type internal StructBox<'T when 'T : equality>(value:'T) = + member x.Value = value + static member Comparer = + let gcomparer = HashIdentity.Structural<'T> + { new IEqualityComparer> with + member __.GetHashCode(v) = gcomparer.GetHashCode(v.Value) + member __.Equals(v1,v2) = gcomparer.Equals(v1.Value,v2.Value) } + + let inline checkNonNull argName arg = + match box arg with + | null -> nullArg argName + | _ -> () + + let mkSeq f = + { new IEnumerable<'U> with + member x.GetEnumerator() = f() + interface IEnumerable with + member x.GetEnumerator() = (f() :> IEnumerator) } + + [] + type EmptyEnumerable<'T> = + | EmptyEnumerable + interface IEnumerable<'T> with + member x.GetEnumerator() = IEnumerator.Empty<'T>() + interface IEnumerable with + member x.GetEnumerator() = (IEnumerator.Empty<'T>() :> IEnumerator) + + let Generate openf compute closef = + mkSeq (fun () -> IEnumerator.generateWhileSome openf compute closef) + + let GenerateUsing (openf : unit -> ('U :> System.IDisposable)) compute = + Generate openf compute (fun (s:'U) -> s.Dispose()) + + let EnumerateFromFunctions opener moveNext current = + Generate + opener + (fun x -> if moveNext x then Some(current x) else None) + (fun x -> match box(x) with :? System.IDisposable as id -> id.Dispose() | _ -> ()) + + // A family of enumerators that can have additional 'finally' actions added to the enumerator through + // the use of mutation. This is used to 'push' the disposal action for a 'use' into the next enumerator. + // For example, + // seq { use x = ... + // while ... } + // results in the 'while' loop giving an adjustable enumerator. This is then adjusted by adding the disposal action + // from the 'use' into the enumerator. This means that we avoid constructing a two-deep enumerator chain in this + // common case. + type IFinallyEnumerator = + abstract AppendFinallyAction : (unit -> unit) -> unit + + /// A concrete implementation of IEnumerable that adds the given compensation to the "Dispose" chain of any + /// enumerators returned by the enumerable. + [] + type FinallyEnumerable<'T>(compensation: unit -> unit, restf: unit -> seq<'T>) = + interface IEnumerable<'T> with + member x.GetEnumerator() = + try + let ie = restf().GetEnumerator() + match ie with + | :? IFinallyEnumerator as a -> + a.AppendFinallyAction(compensation) + ie + | _ -> + IEnumerator.EnumerateThenFinally compensation ie + with e -> + compensation() + reraise() + interface IEnumerable with + member x.GetEnumerator() = ((x :> IEnumerable<'T>).GetEnumerator() :> IEnumerator) + + /// An optimized object for concatenating a sequence of enumerables + [] + type ConcatEnumerator<'T,'U when 'U :> seq<'T>>(sources: seq<'U>) = + let mutable outerEnum = sources.GetEnumerator() + let mutable currInnerEnum = IEnumerator.Empty() + + let mutable started = false + let mutable finished = false + let mutable compensations = [] + + [] // false = unchecked + val mutable private currElement : 'T + + member x.Finish() = + finished <- true + try + match currInnerEnum with + | null -> () + | _ -> + try + currInnerEnum.Dispose() + finally + currInnerEnum <- null + finally + try + match outerEnum with + | null -> () + | _ -> + try + outerEnum.Dispose() + finally + outerEnum <- null + finally + let rec iter comps = + match comps with + | [] -> () + | h::t -> + try h() finally iter t + try + compensations |> List.rev |> iter + finally + compensations <- [] + + member x.GetCurrent() = + IEnumerator.check started + if finished then IEnumerator.alreadyFinished() else x.currElement + + interface IFinallyEnumerator with + member x.AppendFinallyAction(f) = + compensations <- f :: compensations + + interface IEnumerator<'T> with + member x.Current = x.GetCurrent() + + interface IEnumerator with + member x.Current = box (x.GetCurrent()) + + member x.MoveNext() = + if not started then (started <- true) + if finished then false + else + let rec takeInner () = + // check the inner list + if currInnerEnum.MoveNext() then + x.currElement <- currInnerEnum.Current + true + else + // check the outer list + let rec takeOuter() = + if outerEnum.MoveNext() then + let ie = outerEnum.Current + // Optimization to detect the statically-allocated empty IEnumerables + match box ie with + | :? EmptyEnumerable<'T> -> + // This one is empty, just skip, don't call GetEnumerator, try again + takeOuter() + | _ -> + // OK, this one may not be empty. + // Don't forget to dispose of the enumerator for the inner list now we're done with it + currInnerEnum.Dispose() + currInnerEnum <- ie.GetEnumerator() + takeInner () + else + // We're done + x.Finish() + false + takeOuter() + takeInner () + + member x.Reset() = IEnumerator.noReset() + + interface System.IDisposable with + member x.Dispose() = + if not finished then + x.Finish() + + let EnumerateUsing (resource : 'T :> System.IDisposable) (rest: 'T -> #seq<'U>) = + (FinallyEnumerable((fun () -> match box resource with null -> () | _ -> resource.Dispose()), + (fun () -> rest resource :> seq<_>)) :> seq<_>) + + let mkConcatSeq (sources: seq<'U :> seq<'T>>) = + mkSeq (fun () -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>) + + let EnumerateWhile (g : unit -> bool) (b: seq<'T>) : seq<'T> = + let started = ref false + let curr = ref None + let getCurr() = + IEnumerator.check !started + match !curr with None -> IEnumerator.alreadyFinished() | Some x -> x + let start() = if not !started then (started := true) + + let finish() = (curr := None) + mkConcatSeq + (mkSeq (fun () -> + { new IEnumerator<_> with + member x.Current = getCurr() + interface IEnumerator with + member x.Current = box (getCurr()) + member x.MoveNext() = + start() + let keepGoing = (try g() with e -> finish (); reraise ()) in + if keepGoing then + curr := Some(b); true + else + finish(); false + member x.Reset() = IEnumerator.noReset() + interface System.IDisposable with + member x.Dispose() = () })) + + let EnumerateThenFinally (rest : seq<'T>) (compensation : unit -> unit) = + (FinallyEnumerable(compensation, (fun () -> rest)) :> seq<_>) + + let CreateEvent (add : 'Delegate -> unit) (remove : 'Delegate -> unit) (create : (obj -> 'Args -> unit) -> 'Delegate ) :IEvent<'Delegate,'Args> = + // Note, we implement each interface explicitly: this works around a bug in the CLR + // implementation on CompactFramework 3.7, used on Windows Phone 7 + { new obj() with + member x.ToString() = "" + interface IEvent<'Delegate,'Args> + interface IDelegateEvent<'Delegate> with + member x.AddHandler(h) = add h + member x.RemoveHandler(h) = remove h + interface System.IObservable<'Args> with + member x.Subscribe(r:IObserver<'Args>) = + let h = create (fun _ args -> r.OnNext(args)) + add h + { new System.IDisposable with + member x.Dispose() = remove h } } + + + [] + type GeneratedSequenceBase<'T>() = + let mutable redirectTo : GeneratedSequenceBase<'T> = Unchecked.defaultof<_> + let mutable redirect : bool = false + + abstract GetFreshEnumerator : unit -> IEnumerator<'T> + abstract GenerateNext : next:byref> -> int // 0 = Stop, 1 = Yield, 2 = Goto + abstract Close: unit -> unit + abstract CheckClose: bool + abstract LastGenerated : 'T + + //[] + member x.MoveNextImpl() = + let active = + if redirect then redirectTo + else x + let mutable target = null + match active.GenerateNext(&target) with + | 1 -> + true + | 2 -> + match target.GetEnumerator() with + | :? GeneratedSequenceBase<'T> as g when not active.CheckClose -> + redirectTo <- g + | e -> + redirectTo <- + { new GeneratedSequenceBase<'T>() with + member x.GetFreshEnumerator() = e + member x.GenerateNext(_) = if e.MoveNext() then 1 else 0 + member x.Close() = try e.Dispose() finally active.Close() + member x.CheckClose = true + member x.LastGenerated = e.Current } + redirect <- true + x.MoveNextImpl() + | _ (* 0 *) -> + false + + interface IEnumerable<'T> with + member x.GetEnumerator() = x.GetFreshEnumerator() + interface IEnumerable with + member x.GetEnumerator() = (x.GetFreshEnumerator() :> IEnumerator) + interface IEnumerator<'T> with + member x.Current = if redirect then redirectTo.LastGenerated else x.LastGenerated + member x.Dispose() = if redirect then redirectTo.Close() else x.Close() + interface IEnumerator with + member x.Current = box (if redirect then redirectTo.LastGenerated else x.LastGenerated) + + //[] + member x.MoveNext() = x.MoveNextImpl() + + member x.Reset() = raise <| new System.NotSupportedException() + + namespace Microsoft.FSharp.Collections open System @@ -16,6 +459,11 @@ namespace Microsoft.FSharp.Collections open Microsoft.FSharp.Primitives.Basics open Microsoft.FSharp.Collections.IEnumerator + module Upcast = + // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality + // is fixed with the compiler then these functions can be removed. + let inline enumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) + [] type CachedSeq<'T>(cleanup,res:seq<'T>) = interface System.IDisposable with @@ -30,68 +478,949 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = +// type ISeqEnumerable<'T> = +// abstract member Fold<'State> : folder:('State->'T->'State) -> state:'State -> 'State + + module SeqComposer = + open IEnumerator + + type ISeqComponent = + abstract OnComplete : unit -> unit + abstract OnDispose : unit -> unit + + module Helpers = + // used for performance reasons; these are not recursive calls, so should be safe + // ** it should be noted that potential changes to the f# compiler may render this function + // ineffictive ** + let inline avoidTailCall boolean = match boolean with true -> true | false -> false + + // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality + // is fixed with the compiler then these functions can be removed. + let inline upcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) + let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) + let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) + let inline upcastISeqComponent (t:#ISeqComponent) : ISeqComponent = (# "" t : ISeqComponent #) + + type SeqProcessNextStates = + | InProcess = 0 + | NotStarted = 1 + | Finished = 2 + + type Result<'T>() = + let mutable halted = false + + member val SeqState = SeqProcessNextStates.NotStarted with get, set + + member __.StopFurtherProcessing () = halted <- true + member __.Halted = halted + + member val Current = Unchecked.defaultof<'T> with get, set + + let seqComponentTail = + { new ISeqComponent with + member __.OnComplete() = () + member __.OnDispose() = () } + + type [] SeqComponentFactory<'T,'U> () = + abstract Create<'V> : Result<'V> -> SeqComponent<'U,'V> -> SeqComponent<'T,'V> + abstract IsIdentity : bool + + default __.IsIdentity = false + + and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>) = + inherit SeqComponentFactory<'T,'V> () + override __.Create<'W> (result:Result<'W>) (next:SeqComponent<'V,'W>) : SeqComponent<'T,'W> = first.Create result (second.Create result next) + + static member Combine (first:SeqComponentFactory<'T,'U>) (second:SeqComponentFactory<'U,'V>) : SeqComponentFactory<'T,'V> = + let castToTV (factory:obj) = + match factory with + | :? SeqComponentFactory<'T,'V> as result -> result + | _ -> failwith "library implementation error: they types must match when paired with identity" + + if first.IsIdentity then castToTV second + elif second.IsIdentity then castToTV first + else upcast ComposedFactory(first, second) + + and ChooseFactory<'T,'U> (filter:'T->option<'U>) = + inherit SeqComponentFactory<'T,'U> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Choose (filter, next) + + and DistinctFactory<'T when 'T: equality> () = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Distinct (next) + + and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast DistinctBy (keyFunction, next) + + and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Except (itemsToExclude, next) + + and FilterFactory<'T> (filter:'T->bool) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = next.CreateFilter filter + + and IdentityFactory<'T> () = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = next.CreateMap id + override __.IsIdentity = true + + and MapFactory<'T,'U> (map:'T->'U) = + inherit SeqComponentFactory<'T,'U> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = next.CreateMap map + + and Map2Factory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = + inherit SeqComponentFactory<'First,'U> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map2 (map, input2, result, next) + + and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = + inherit SeqComponentFactory<'First,'U> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map3 (map, input2, input3, result, next) + + and MapiFactory<'T,'U> (mapi:int->'T->'U) = + inherit SeqComponentFactory<'T,'U> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Mapi (mapi, next) + + and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = + inherit SeqComponentFactory<'First,'U> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Mapi2 (map, input2, result, next) + + and PairwiseFactory<'T> () = + inherit SeqComponentFactory<'T,'T*'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T*'T,'V>) : SeqComponent<'T,'V> = upcast Pairwise next + + and SkipFactory<'T> (count:int) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Skip (count, next) + + and SkipWhileFactory<'T> (predicate:'T->bool) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast SkipWhile (predicate, next) + + and TakeWhileFactory<'T> (predicate:'T->bool) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast TakeWhile (predicate, result, next) + + and TakeFactory<'T> (count:int) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Take (count, result, next) + + and TruncateFactory<'T> (count:int) = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Truncate (count, result, next) + + and [] SeqComponent<'T,'U> (next:ISeqComponent) = + abstract ProcessNext : input:'T -> bool + + // Seq.init(Infinite)? lazily uses Current. The only SeqComposer component that can do that is Skip + // and it can only do it at the start of a sequence + abstract Skipping : unit -> bool + + abstract CreateMap<'S> : map:('S->'T) -> SeqComponent<'S,'U> + abstract CreateFilter : filter:('T->bool) -> SeqComponent<'T,'U> + + interface ISeqComponent with + member __.OnComplete () = next.OnComplete () + member __.OnDispose () = next.OnDispose () + + default __.Skipping () = false + + default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) + default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) + + and Choose<'T,'U,'V> (choose:'T->option<'U>, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + match choose input with + | Some value -> Helpers.avoidTailCall (next.ProcessNext value) + | None -> false + + and Distinct<'T,'V when 'T: equality> (next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) + + override __.ProcessNext (input:'T) : bool = + if hashSet.Add input then + Helpers.avoidTailCall (next.ProcessNext input) + else + false + + and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) + + override __.ProcessNext (input:'T) : bool = + if hashSet.Add(keyFunction input) then + Helpers.avoidTailCall (next.ProcessNext input) + else + false + + and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) + + override __.ProcessNext (input:'T) : bool = + if cached.Value.Add input then + Helpers.avoidTailCall (next.ProcessNext input) + else + false + + and Filter<'T,'V> (filter:'T->bool, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) + + override __.ProcessNext (input:'T) : bool = + if filter input then + Helpers.avoidTailCall (next.ProcessNext input) + else + false + + and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + if filter input then + Helpers.avoidTailCall (next.ProcessNext (map input)) + else + false + + and Map<'T,'U,'V> (map:'T->'U, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) + + override __.ProcessNext (input:'T) : bool = + Helpers.avoidTailCall (next.ProcessNext (map input)) + + and Map2<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'First,'V>(next) + + let input2 = enumerable2.GetEnumerator () + let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map + + override __.ProcessNext (input:'First) : bool = + if input2.MoveNext () then + Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) + else + result.StopFurtherProcessing () + false + + interface ISeqComponent with + override __.OnDispose () = + try + input2.Dispose () + finally + (Helpers.upcastISeqComponent next).OnDispose () + + and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:Result<'V>, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'First,'V>(next) + + let input2 = enumerable2.GetEnumerator () + let input3 = enumerable3.GetEnumerator () + let map' = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt map + + override __.ProcessNext (input:'First) : bool = + if input2.MoveNext () && input3.MoveNext () then + Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) + else + result.StopFurtherProcessing () + false + + interface ISeqComponent with + override __.OnDispose () = + try + input2.Dispose () + finally + try + input3.Dispose () + finally + (Helpers.upcastISeqComponent next).OnDispose () + + and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + let u = map input + if filter u then + Helpers.avoidTailCall (next.ProcessNext u) + else + false + + and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable idx = 0 + let mapi' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt mapi + + override __.ProcessNext (input:'T) : bool = + idx <- idx + 1 + Helpers.avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) + + and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'First,'V>(next) + + let mutable idx = 0 + let input2 = enumerable2.GetEnumerator () + let mapi2' = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt map + + override __.ProcessNext (input:'First) : bool = + if input2.MoveNext () then + idx <- idx + 1 + Helpers.avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) + else + result.StopFurtherProcessing () + false + + interface ISeqComponent with + override __.OnDispose () = + try + input2.Dispose () + finally + (Helpers.upcastISeqComponent next).OnDispose () + + and Pairwise<'T,'V> (next:SeqComponent<'T*'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable isFirst = true + let mutable lastValue = Unchecked.defaultof<'T> + + override __.ProcessNext (input:'T) : bool = + if isFirst then + lastValue <- input + isFirst <- false + false + else + let currentPair = lastValue, input + lastValue <- input + Helpers.avoidTailCall (next.ProcessNext currentPair) + + and Skip<'T,'V> (skipCount:int, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable count = 0 + + override __.Skipping () = + if count < skipCount then + count <- count + 1 + true + else + false + + override __.ProcessNext (input:'T) : bool = + if count < skipCount then + count <- count + 1 + false + else + Helpers.avoidTailCall (next.ProcessNext input) + + interface ISeqComponent with + override __.OnComplete () = + if count < skipCount then + let x = skipCount - count + invalidOpFmt "tried to skip {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + (Helpers.upcastISeqComponent next).OnComplete () + + and SkipWhile<'T,'V> (predicate:'T->bool, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable skip = true + + override __.ProcessNext (input:'T) : bool = + if skip then + skip <- predicate input + if skip then + false + else + Helpers.avoidTailCall (next.ProcessNext input) + else + Helpers.avoidTailCall (next.ProcessNext input) + + and Take<'T,'V> (takeCount:int, result:Result<'V>, next:SeqComponent<'T,'V>) = + inherit Truncate<'T, 'V>(takeCount, result, next) + + interface ISeqComponent with + override this.OnComplete () = + if this.Count < takeCount then + let x = takeCount - this.Count + invalidOpFmt "tried to take {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + (Helpers.upcastISeqComponent next).OnComplete () + + and TakeWhile<'T,'V> (predicate:'T->bool, result:Result<'V>, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + if predicate input then + next.ProcessNext input + else + result.StopFurtherProcessing () + false + + and Tail<'T> (result:Result<'T>) = + inherit SeqComponent<'T,'T>(seqComponentTail) + + override __.ProcessNext (input:'T) : bool = + result.Current <- input + true + + and Truncate<'T,'V> (truncateCount:int, result:Result<'V>, next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable count = 0 + + member __.Count = count + + override __.ProcessNext (input:'T) : bool = + if count < truncateCount then + count <- count + 1 + if count = truncateCount then + result.StopFurtherProcessing () + next.ProcessNext input + else + result.StopFurtherProcessing () + false + + module Enumerable = + [] + type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ISeqComponent) = + interface IDisposable with + member __.Dispose() : unit = + seqComponent.OnDispose () + + interface IEnumerator with + member this.Current : obj = box ((Helpers.upcastEnumerator this)).Current + member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)" + member __.Reset () : unit = noReset () + + interface IEnumerator<'T> with + member __.Current = + if result.SeqState = SeqProcessNextStates.InProcess then result.Current + else + match result.SeqState with + | SeqProcessNextStates.NotStarted -> notStarted() + | SeqProcessNextStates.Finished -> alreadyFinished() + | _ -> failwith "library implementation error: all states should have been handled" + + and [] EnumerableBase<'T> () = + abstract member Compose<'U> : (SeqComponentFactory<'T,'U>) -> IEnumerable<'U> + abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> + abstract member Fold<'State> : folder:('State->'T->'State) -> state:'State -> 'State + + default this.Append source = Helpers.upcastEnumerable (AppendEnumerable [this; source]) + + interface IEnumerable with + member this.GetEnumerator () : IEnumerator = + let genericEnumerable = Helpers.upcastEnumerable this + let genericEnumerator = genericEnumerable.GetEnumerator () + Helpers.upcastEnumeratorNonGeneric genericEnumerator + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = failwith "library implementation error: derived class should implement (should be abstract)" + + and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + inherit EnumeratorBase<'U>(result, seqComponent) + + let rec moveNext () = + if (not result.Halted) && source.MoveNext () then + if seqComponent.ProcessNext source.Current then + true + else + moveNext () + else + result.SeqState <- SeqProcessNextStates.Finished + (Helpers.upcastISeqComponent seqComponent).OnComplete () + false + + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext () + + interface IDisposable with + member __.Dispose() = + try + source.Dispose () + finally + (Helpers.upcastISeqComponent seqComponent).OnDispose () + + and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqComponentFactory<'T,'U>) = + inherit EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (Tail result), result)) + + override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = + Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) + + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let enumerator = enumerable.GetEnumerator () + let result = Result<'U> () + + let components = current.Create result (Tail result) + + let mutable state = initialState + while (not result.Halted) && (enumerator.MoveNext ()) do + if components.ProcessNext (enumerator.Current) then + state <- folder'.Invoke (state, result.Current) + + state + + and AppendEnumerator<'T> (sources:list>) = + let sources = sources |> List.rev + + let mutable state = SeqProcessNextStates.NotStarted + let mutable remaining = sources.Tail + let mutable active = sources.Head.GetEnumerator () + + let rec moveNext () = + if active.MoveNext () then true + else + match remaining with + | [] -> false + | hd :: tl -> + active.Dispose () + active <- hd.GetEnumerator () + remaining <- tl + + moveNext () + + interface IEnumerator<'T> with + member __.Current = + if state = SeqProcessNextStates.InProcess then active.Current + else + match state with + | SeqProcessNextStates.NotStarted -> notStarted() + | SeqProcessNextStates.Finished -> alreadyFinished() + | _ -> failwith "library implementation error: all states should have been handled" + + interface IEnumerator with + member this.Current = box ((Helpers.upcastEnumerator this)).Current + member __.MoveNext () = + state <- SeqProcessNextStates.InProcess + moveNext () + member __.Reset () = noReset () + + interface IDisposable with + member __.Dispose() = + active.Dispose () + + and AppendEnumerable<'T> (sources:list>) = + inherit EnumerableBase<'T>() + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = + Helpers.upcastEnumerator (new AppendEnumerator<_> (sources)) + + override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = + Helpers.upcastEnumerable (Enumerable<'T,'V>(this, next)) + + override this.Append source = + Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) + + override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) + let enumerator = enumerable.GetEnumerator () + + let mutable state = initialState + while enumerator.MoveNext () do + state <- folder'.Invoke (state, enumerator.Current) + + state + + module Array = + type Enumerator<'T,'U>(array:array<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + + let mutable idx = 0 + + let rec moveNext () = + if (not result.Halted) && idx < array.Length then + idx <- idx+1 + if seqComponent.ProcessNext array.[idx-1] then + true + else + moveNext () + else + result.SeqState <- SeqProcessNextStates.Finished + (Helpers.upcastISeqComponent seqComponent).OnComplete () + false + + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext () + + type Enumerable<'T,'U>(array:array<'T>, current:SeqComponentFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Helpers.upcastEnumerator (new Enumerator<'T,'U>(array, current.Create result (Tail result), result)) + + override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = + Helpers.upcastEnumerable (new Enumerable<'T,'V>(array, ComposedFactory.Combine current next)) + + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let mutable idx = 0 + let result = Result<'U> () + let components = current.Create result (Tail result) + + let mutable state = initialState + while (not result.Halted) && (idx < array.Length) do + if components.ProcessNext array.[idx] then + state <- folder'.Invoke (state, result.Current) + idx <- idx + 1 + + state + + module List = + type Enumerator<'T,'U>(alist:list<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + + let mutable list = alist + + let rec moveNext current = + match result.Halted, current with + | false, head::tail -> + if seqComponent.ProcessNext head then + list <- tail + true + else + moveNext tail + | _ -> + result.SeqState <- SeqProcessNextStates.Finished + (Helpers.upcastISeqComponent seqComponent).OnComplete () + false + + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext list + + type Enumerable<'T,'U>(alist:list<'T>, current:SeqComponentFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (Tail result), result)) + + override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = + Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) + + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let result = Result<'U> () + let components = current.Create result (Tail result) + + let rec fold state lst = + match result.Halted, lst with + | true, _ + | false, [] -> state + | false, hd :: tl -> + if components.ProcessNext hd then + fold (folder'.Invoke (state, result.Current)) tl + else + fold state tl + + fold initialState alist + + module Unfold = + type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:SeqComponent<'T,'U>, signal:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) + + let mutable current = state + + let rec moveNext () = + match generator current with + | None -> false + | Some (item, nextState) -> + current <- nextState + if seqComponent.ProcessNext item then + true + else + moveNext () + + interface IEnumerator with + member __.MoveNext () = + signal.SeqState <- SeqProcessNextStates.InProcess + moveNext () + + type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqComponentFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (Tail result), result)) + + override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = + Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let result = Result<'U> () + let components = current.Create result (Tail result) + + let rec fold state current = + match result.Halted, generator current with + | true, _ + | false, None -> state + | false, Some (item, next) -> + if components.ProcessNext item then + fold (folder'.Invoke (state, result.Current)) next + else + fold state next + + fold initialState state + + module Init = + // The original implementation of "init" delayed the calculation of Current, and so it was possible + // to do MoveNext without it's value being calculated. + // I can imagine only two scenerios where that is possibly sane, although a simple solution is readily + // at hand in both cases. The first is that of an expensive generator function, where you skip the + // first n elements. The simple solution would have just been to have a map ((+) n) as the first operation + // instead. The second case would be counting elements, but that is only of use if you're not filtering + // or mapping or doing anything else (as that would cause Current to be evaluated!) and + // so you already know what the count is!! Anyway, someone thought it was a good idea, so + // I have had to add an extra function that is used in Skip to determine if we are touching + // Current or not. + + let getTerminatingIdx (count:Nullable) = + // we are offset by 1 to allow for values going up to System.Int32.MaxValue + // System.Int32.MaxValue is an illegal value for the "infinite" sequence + if count.HasValue then + count.Value - 1 + else + System.Int32.MaxValue + + type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:SeqComponent<'T,'U>, signal:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) + + let terminatingIdx = + getTerminatingIdx count + + let mutable maybeSkipping = true + let mutable idx = -1 + + let rec moveNext () = + if (not signal.Halted) && idx < terminatingIdx then + idx <- idx + 1 + + if maybeSkipping then + // Skip can only is only checked at the start of the sequence, so once + // triggered, we stay triggered. + maybeSkipping <- seqComponent.Skipping () + + if maybeSkipping then + moveNext () + elif seqComponent.ProcessNext (f idx) then + true + else + moveNext () + elif (not signal.Halted) && idx = System.Int32.MaxValue then + raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) + else + signal.SeqState <- SeqProcessNextStates.Finished + (Helpers.upcastISeqComponent seqComponent).OnComplete () + false + + interface IEnumerator with + member __.MoveNext () = + signal.SeqState <- SeqProcessNextStates.InProcess + moveNext () + + type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqComponentFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (Tail result), result)) + + override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = + Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let result = Result<'U> () + let components = current.Create result (Tail result) + + let mutable idx = -1 + let terminatingIdx = getTerminatingIdx count + + let mutable maybeSkipping = true + + let mutable state = initialState + while (not result.Halted) && (idx < terminatingIdx) do + if maybeSkipping then + maybeSkipping <- components.Skipping () + + if (not maybeSkipping) && (components.ProcessNext (f (idx+1))) then + state <- folder'.Invoke (state, result.Current) + + idx <- idx + 1 + + state + + let upto lastOption f = + match lastOption with + | Some b when b<0 -> failwith "library implementation error: upto can never be called with a negative value" + | _ -> + let unstarted = -1 // index value means unstarted (and no valid index) + let completed = -2 // index value means completed (and no valid index) + let unreachable = -3 // index is unreachable from 0,1,2,3,... + let finalIndex = match lastOption with + | Some b -> b // here b>=0, a valid end value. + | None -> unreachable // run "forever", well as far as Int32.MaxValue since indexing with a bounded type. + // The Current value for a valid index is "f i". + // Lazy<_> values are used as caches, to store either the result or an exception if thrown. + // These "Lazy<_>" caches are created only on the first call to current and forced immediately. + // The lazy creation of the cache nodes means enumerations that skip many Current values are not delayed by GC. + // For example, the full enumeration of Seq.initInfinite in the tests. + // state + let index = ref unstarted + // a Lazy node to cache the result/exception + let current = ref (Unchecked.defaultof<_>) + let setIndex i = index := i; current := (Unchecked.defaultof<_>) // cache node unprimed, initialised on demand. + let getCurrent() = + if !index = unstarted then notStarted() + if !index = completed then alreadyFinished() + match box !current with + | null -> current := Lazy<_>.Create(fun () -> f !index) + | _ -> () + // forced or re-forced immediately. + (!current).Force() + { new IEnumerator<'U> with + member x.Current = getCurrent() + interface IEnumerator with + member x.Current = box (getCurrent()) + member x.MoveNext() = + if !index = completed then + false + elif !index = unstarted then + setIndex 0 + true + else ( + if !index = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) + if !index = finalIndex then + false + else + setIndex (!index + 1) + true + ) + member self.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = () } + + type EnumerableDecider<'T>(count:Nullable, f:int->'T) = + inherit Enumerable.EnumerableBase<'T>() + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = + // we defer back to the original implementation as, as it's quite idiomatic in it's decision + // to calculate Current in a lazy fashion. I doubt anyone is really using this functionality + // in the way presented, but it's possible. + upto (if count.HasValue then Some (count.Value-1) else None) f + + override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = + Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) + + override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = + let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + + let enumerator = (Helpers.upcastEnumerable this).GetEnumerator () + + let mutable state = initialState + while enumerator.MoveNext () do + state <- folder'.Invoke (state, enumerator.Current) + + state + #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions #else #endif - let mkDelayedSeq (f: unit -> IEnumerable<'T>) = mkSeq (fun () -> f().GetEnumerator()) let inline indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) [] let toComposer (source:seq<'T>): Composer.Core.ISeq<'T> = Composer.Seq.toComposer source - + let inline foreach f (source:seq<_>) = Composer.Seq.foreach f (toComposer source) + let private seqFactory createSeqComponent (source:seq<'T>) = + match source with + | :? Composer.Core.ISeq<'T> as s -> Upcast.enumerable (s.Compose createSeqComponent) + | :? array<'T> as a -> Upcast.enumerable (Composer.Seq.Array.create a createSeqComponent) + | :? list<'T> as a -> Upcast.enumerable (Composer.Seq.List.create a createSeqComponent) + | null -> nullArg "source" + | _ -> Upcast.enumerable (Composer.Seq.Enumerable.create source createSeqComponent) + [] let delay f = mkDelayedSeq f [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> = - Composer.Seq.unfold generator state - |> Composer.Helpers.upcastEnumerable + SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Unfold.Enumerable<'T,'T,'State>(generator, state, SeqComposer.IdentityFactory ())) [] let empty<'T> = (EmptyEnumerable :> seq<'T>) [] let initInfinite<'T> (f:int->'T) : IEnumerable<'T> = - Composer.Seq.initInfinite f - |> Composer.Helpers.upcastEnumerable + SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Init.EnumerableDecider<'T>(Nullable (), f)) [] let init<'T> (count:int) (f:int->'T) : IEnumerable<'T> = - Composer.Seq.init count f - |> Composer.Helpers.upcastEnumerable + if count < 0 then invalidArgInputMustBeNonNegative "count" count + elif count = 0 then empty else + SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Init.EnumerableDecider<'T>(Nullable count, f)) [] let iter f (source : seq<'T>) = Composer.Seq.iter f (toComposer source) + [] + let tryHead (source : seq<_>) = + Composer.Seq.tryHead (toComposer source) + + [] + let skip count (source: seq<_>) = + source |> seqFactory (Composer.Seq.SkipFactory (count, invalidOpFmt)) + + let invalidArgumnetIndex = invalidArgFmt "index" + [] let item i (source : seq<'T>) = if i < 0 then invalidArgInputMustBeNonNegative "index" i else - source - |> foreach (fun halt -> - { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values<_,_,_> (0, false, Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - if this.Value._1 = i then - this.Value._2 <- true - this.Value._3 <- value - halt () - else - this.Value._1 <- this.Value._1 + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - override this.OnComplete _ = - if not this.Value._2 then - let index = i - this.Value._1 + 1 - invalidArgFmt "index" - "{0}\nseq was short by {1} {2}" - [|SR.GetString SR.notEnoughElements; index; (if index=1 then "element" else "elements")|] - }) - |> fun item -> item.Value._3 + source + |> seqFactory (Composer.Seq.SkipFactory (i, invalidArgumnetIndex)) + |> tryHead + |> function + | None -> invalidArgFmt "index" "{0}\nseq was short by 1 element" [|SR.GetString SR.notEnoughElements|] + | Some value -> value [] let tryItem i (source:seq<'T>) = @@ -163,15 +1492,15 @@ namespace Microsoft.FSharp.Collections let private seqFactory createSeqComponent (source:seq<'T>) = checkNonNull "source" source match source with - | :? Composer.Core.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose createSeqComponent) - | :? array<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.Seq.Array.create a createSeqComponent) - | :? list<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.Seq.List.create a createSeqComponent) - | _ -> Composer.Helpers.upcastEnumerable (Composer.Seq.Enumerable.create source createSeqComponent) + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Compose createSeqComponent + | :? array<'T> as a -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Array.Enumerable<_,_>(a, createSeqComponent)) + | :? list<'T> as a -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.List.Enumerable<_,_>(a, createSeqComponent)) + | _ -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Enumerable.Enumerable<_,_>(source, createSeqComponent)) [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = Composer.Seq.filter f (toComposer source) - |> Composer.Helpers.upcastEnumerable + |> Upcast.enumerable [] let where f source = filter f source @@ -179,40 +1508,39 @@ namespace Microsoft.FSharp.Collections [] let map<'T,'U> (f:'T->'U) (source:seq<'T>) : seq<'U> = Composer.Seq.map f (toComposer source) - |> Composer.Helpers.upcastEnumerable + |> Upcast.enumerable [] - let mapi f source = - Composer.Seq.mapi f (toComposer source) - |> Composer.Helpers.upcastEnumerable + let mapi f source = + let f' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f + Composer.Seq.mapi_adapt f' (toComposer source) + |> Upcast.enumerable [] let mapi2 f source1 source2 = checkNonNull "source2" source2 - source1 |> seqFactory (Composer.Seq.Mapi2Factory (f, source2)) + source1 |> seqFactory (SeqComposer.Mapi2Factory (f, source2)) [] let map2<'T,'U,'V> (f:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = checkNonNull "source1" source1 - match source1 with - | :? Composer.Core.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose (Composer.Seq.Map2FirstFactory (f, source2))) - | _ -> source2 |> seqFactory (Composer.Seq.Map2SecondFactory (f, source1)) + source1 |> seqFactory (SeqComposer.Map2Factory (f, source2)) [] let map3 f source1 source2 source3 = checkNonNull "source2" source2 checkNonNull "source3" source3 - source1 |> seqFactory (Composer.Seq.Map3Factory (f, source2, source3)) + source1 |> seqFactory (SeqComposer.Map3Factory (f, source2, source3)) [] let choose f source = Composer.Seq.choose f (toComposer source) - |> Composer.Helpers.upcastEnumerable + |> Upcast.enumerable [] let indexed source = Composer.Seq.indexed (toComposer source) - |> Composer.Helpers.upcastEnumerable + |> Upcast.enumerable [] let zip source1 source2 = @@ -344,8 +1672,8 @@ namespace Microsoft.FSharp.Collections checkNonNull "source1" source1 checkNonNull "source2" source2 match source1 with - | :? Composer.Seq.Enumerable.EnumerableBase<'T> as s -> s.Append source2 - | _ -> Composer.Helpers.upcastEnumerable (new Composer.Seq.Enumerable.AppendEnumerable<_>([source2; source1])) + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Append source2 + | _ -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Enumerable.AppendEnumerable<_>([source2; source1])) [] @@ -389,7 +1717,7 @@ namespace Microsoft.FSharp.Collections [] let ofArray (source : 'T array) = checkNonNull "source" source - Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createId source) + Upcast.enumerable (Composer.Seq.Array.createId source) [] let toArray (source : seq<'T>) = @@ -639,7 +1967,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceBy keyf array array - Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedSort) + Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedSort) [] let sort source = @@ -648,7 +1976,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlace array array - Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedSort) + Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedSort) [] let sortWith f source = @@ -657,7 +1985,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceWith f array array - Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedSort) + Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedSort) [] let inline sortByDescending keyf source = @@ -875,10 +2203,6 @@ namespace Microsoft.FSharp.Collections let takeWhile p (source: seq<_>) = source |> seqFactory (Composer.Seq.TakeWhileFactory p) - [] - let skip count (source: seq<_>) = - source |> seqFactory (Composer.Seq.SkipFactory count) - [] let skipWhile p (source: seq<_>) = source |> seqFactory (Composer.Seq.SkipWhileFactory p) @@ -923,17 +2247,6 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun exists -> exists.Value - [] - let tryHead (source : seq<_>) = - source - |> foreach (fun halt -> - { new Composer.Core.Folder<'T, Option<'T>> (None) with - override this.ProcessNext value = - this.Value <- Some value - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun head -> head.Value - [] let head (source : seq<_>) = match tryHead source with @@ -994,7 +2307,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.Reverse array array - Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedReverse) + Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedReverse) [] let permute f (source:seq<_>) = @@ -1003,7 +2316,7 @@ namespace Microsoft.FSharp.Collections source |> toArray |> Array.permute f - Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedPermute) + Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedPermute) [] let mapFold<'T,'State,'Result> (f: 'State -> 'T -> 'Result * 'State) acc source = diff --git a/src/fsharp/FSharp.Core/seqcomposer.fs b/src/fsharp/FSharp.Core/seqcomposer.fs index 3f36e2c1469..6ebe4e26cf8 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fs +++ b/src/fsharp/FSharp.Core/seqcomposer.fs @@ -14,21 +14,17 @@ namespace Microsoft.FSharp.Collections open Microsoft.FSharp.Control open Microsoft.FSharp.Collections open Microsoft.FSharp.Primitives.Basics - + [] module Composer = open IEnumerator module Core = - type PipeIdx = int - type ``PipeIdx?`` = Nullable - let emptyPipeIdx = Nullable () - let inline getPipeIdx (maybePipeIdx:``PipeIdx?``) = if maybePipeIdx.HasValue then maybePipeIdx.Value else 1 - let inline makePipeIdx (pipeIdx:PipeIdx) = Nullable pipeIdx + type PipeIdx = int type ICompletionChaining = - abstract OnComplete : PipeIdx -> unit - abstract OnDispose : unit -> unit + abstract OnComplete : stopTailCall:byref * PipeIdx -> unit + abstract OnDispose : stopTailCall:byref -> unit type IOutOfBand = abstract StopFurtherProcessing : PipeIdx -> unit @@ -38,16 +34,16 @@ namespace Microsoft.FSharp.Collections abstract ProcessNext : input:'T -> bool abstract OnComplete : PipeIdx -> unit - abstract OnDispose : unit -> unit + abstract OnDispose : unit -> unit default __.OnComplete _ = () default __.OnDispose () = () interface ICompletionChaining with - member this.OnComplete terminatingIdx = + member this.OnComplete (_, terminatingIdx) = this.OnComplete terminatingIdx - member this.OnDispose () = + member this.OnDispose _ = try this.OnDispose () finally () @@ -84,266 +80,209 @@ namespace Microsoft.FSharp.Collections Value = init } - type ISeqFactory<'T,'U> = + [] + type SeqFactory<'T,'U> () = abstract PipeIdx : PipeIdx - abstract Create<'V> : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> + abstract Create<'V> : IOutOfBand -> PipeIdx -> Consumer<'U,'V> -> Consumer<'T,'V> + + default __.PipeIdx = 1 + + member this.Build outOfBand next = this.Create outOfBand 1 next type ISeq<'T> = inherit IEnumerable<'T> - abstract member Compose<'U> : (ISeqFactory<'T,'U>) -> ISeq<'U> + abstract member Compose<'U> : (SeqFactory<'T,'U>) -> ISeq<'U> abstract member ForEach<'consumer when 'consumer :> Consumer<'T,'T>> : f:((unit->unit)->'consumer) -> 'consumer open Core - module internal Helpers = + module internal TailCall = // used for performance reasons; these are not recursive calls, so should be safe // ** it should be noted that potential changes to the f# compiler may render this function // ineffictive ** - let inline avoidTailCall boolean = match boolean with true -> true | false -> false + let inline avoid boolean = match boolean with true -> true | false -> false + module internal Upcast = // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality // is fixed with the compiler then these functions can be removed. - let inline upcastSeq (t:#ISeq<'T>) : ISeq<'T> = (# "" t : ISeq<'T> #) - let inline upcastFactory (t:#ISeqFactory<'T,'U>) : ISeqFactory<'T,'U> = (# "" t : ISeqFactory<'T,'U> #) - let inline upcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) - let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) - let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) - let inline upcastICompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) - - open Helpers + let inline seq (t:#ISeq<'T>) : ISeq<'T> = (# "" t : ISeq<'T> #) + let inline enumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) + let inline enumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) + let inline enumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) + let inline iCompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) module internal Seq = - type [] SeqComponentFactory<'T,'U> (pipeIdx:``PipeIdx?``) = - new() = SeqComponentFactory<'T,'U> (emptyPipeIdx) - - interface ISeqFactory<'T,'U> with - member __.PipeIdx = getPipeIdx pipeIdx - member __.Create<'V> (_:IOutOfBand) (_:``PipeIdx?``) (_:Consumer<'U,'V>) : Consumer<'T,'V> = failwith "library implementation error: Create on base factory should not be called" + type ComposedFactory<'T,'U,'V> private (first:SeqFactory<'T,'U>, second:SeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = + inherit SeqFactory<'T,'V>() - and ComposedFactory<'T,'U,'V> private (first:ISeqFactory<'T,'U>, second:ISeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = - inherit SeqComponentFactory<'T,'V> (makePipeIdx secondPipeIdx) + override __.PipeIdx = + secondPipeIdx - interface ISeqFactory<'T,'V> with - member this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'V,'W>) : Consumer<'T,'W> = - first.Create outOfBand pipeIdx (second.Create outOfBand (makePipeIdx secondPipeIdx) next) + override this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'V,'W>) : Consumer<'T,'W> = + first.Create outOfBand pipeIdx (second.Create outOfBand secondPipeIdx next) - static member Combine (first:ISeqFactory<'T,'U>) (second:ISeqFactory<'U,'V>) : ISeqFactory<'T,'V> = - ComposedFactory(first, second, first.PipeIdx+1) |> upcastFactory + static member Combine (first:SeqFactory<'T,'U>) (second:SeqFactory<'U,'V>) : SeqFactory<'T,'V> = + upcast ComposedFactory(first, second, first.PipeIdx+1) and ChooseFactory<'T,'U> (filter:'T->option<'U>) = - inherit SeqComponentFactory<'T,'U> () - interface ISeqFactory<'T,'U> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) + inherit SeqFactory<'T,'U> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) and DistinctFactory<'T when 'T: equality> () = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) - - and FilterFactory<'T> (filter:'T->bool) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = - match next with - | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter - | _ -> upcast Filter (filter, next) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) and IdentityFactory<'T> () = - inherit SeqComponentFactory<'T,'T> () - static let singleton = IdentityFactory<'T>() - interface ISeqFactory<'T,'T> with - member __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next + inherit SeqFactory<'T,'T> () + static let singleton : SeqFactory<'T,'T> = upcast (IdentityFactory<'T>()) + override __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next static member Instance = singleton - and MapFactory<'T,'U> (map:'T->'U) = - inherit SeqComponentFactory<'T,'U> () - interface ISeqFactory<'T,'U> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = - match next with - | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map - | _ -> upcast Map<_,_,_> (map, next) - and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = - inherit SeqComponentFactory<'First,'U> () - interface ISeqFactory<'First,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, outOfBand, next, getPipeIdx pipeIdx) + inherit SeqFactory<'First,'U> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, outOfBand, next, pipeIdx) and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = - inherit SeqComponentFactory<'Second,'U> () - interface ISeqFactory<'Second,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, outOfBand, next, getPipeIdx pipeIdx) + inherit SeqFactory<'Second,'U> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, outOfBand, next, pipeIdx) and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = - inherit SeqComponentFactory<'First,'U> () - interface ISeqFactory<'First,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, outOfBand, next, getPipeIdx pipeIdx) - - and MapiFactory<'T,'U> (mapi:int->'T->'U) = - inherit SeqComponentFactory<'T,'U> () - interface ISeqFactory<'T,'U> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Mapi (mapi, next) + inherit SeqFactory<'First,'U> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, outOfBand, next, pipeIdx) and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = - inherit SeqComponentFactory<'First,'U> () - interface ISeqFactory<'First,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, outOfBand, next, getPipeIdx pipeIdx) + inherit SeqFactory<'First,'U> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, outOfBand, next, pipeIdx) and PairwiseFactory<'T> () = - inherit SeqComponentFactory<'T,'T*'T> () - interface ISeqFactory<'T,'T*'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) + inherit SeqFactory<'T,'T*'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) and ScanFactory<'T,'State> (folder:'State->'T->'State, initialState:'State) = - inherit SeqComponentFactory<'T,'State> () - interface ISeqFactory<'T,'State> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) + inherit SeqFactory<'T,'State> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) - and SkipFactory<'T> (count:int) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, next) + and SkipFactory<'T> (count:int, onNotEnoughElements) = + inherit SeqFactory<'T,'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, onNotEnoughElements, next) and SkipWhileFactory<'T> (predicate:'T->bool) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) and TakeWhileFactory<'T> (predicate:'T->bool) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, outOfBand, next, getPipeIdx pipeIdx) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, outOfBand, next, pipeIdx) and TakeFactory<'T> (count:int) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, outOfBand, next, getPipeIdx pipeIdx) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, outOfBand, next, pipeIdx) and TailFactory<'T> () = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) and TruncateFactory<'T> (count:int) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, getPipeIdx pipeIdx) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, pipeIdx) and WindowedFactory<'T> (windowSize:int) = - inherit SeqComponentFactory<'T, 'T[]> () - interface ISeqFactory<'T, 'T[]> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T[],'V>) : Consumer<'T,'V> = upcast Windowed (windowSize, next) - - and [] SeqComponent<'T,'U> (next:ICompletionChaining) = - inherit Consumer<'T,'U>() + inherit SeqFactory<'T, 'T[]> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T[],'V>) : Consumer<'T,'V> = upcast Windowed (windowSize, next) + and ISkipping = // Seq.init(Infinite)? lazily uses Current. The only Composer component that can do that is Skip // and it can only do it at the start of a sequence abstract Skipping : unit -> bool - abstract CreateMap<'S> : map:('S->'T) -> SeqComponent<'S,'U> - abstract CreateFilter : filter:('T->bool) -> SeqComponent<'T,'U> + and [] SeqComponentSimple<'T,'U> (next:ICompletionChaining) = + inherit Consumer<'T,'U>() interface ICompletionChaining with - member this.OnComplete terminatingIdx = - this.OnComplete terminatingIdx - next.OnComplete terminatingIdx - member this.OnDispose () = - try this.OnDispose () - finally next.OnDispose () + member this.OnComplete (stopTailCall, terminatingIdx) = + next.OnComplete (&stopTailCall, terminatingIdx) + member this.OnDispose stopTailCall = + next.OnDispose (&stopTailCall) - default __.Skipping () = false + and [] SeqComponentSimpleValue<'T,'U,'Value> = + inherit SeqComponentSimple<'T,'U> - default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) - default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) + val mutable Value : 'Value + + new (next, init) = { + inherit SeqComponentSimple<'T,'U>(next) + Value = init + } + + and [] SeqComponent<'T,'U> (next:ICompletionChaining) = + inherit Consumer<'T,'U>() + + interface ICompletionChaining with + member this.OnComplete (stopTailCall, terminatingIdx) = + this.OnComplete terminatingIdx + next.OnComplete (&stopTailCall, terminatingIdx) + member this.OnDispose stopTailCall = + try this.OnDispose () + finally next.OnDispose (&stopTailCall) and Choose<'T,'U,'V> (choose:'T->option<'U>, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) override __.ProcessNext (input:'T) : bool = match choose input with - | Some value -> avoidTailCall (next.ProcessNext value) + | Some value -> TailCall.avoid (next.ProcessNext value) | None -> false and Distinct<'T,'V when 'T: equality> (next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) override __.ProcessNext (input:'T) : bool = if hashSet.Add input then - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) else false and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) override __.ProcessNext (input:'T) : bool = if hashSet.Add(keyFunction input) then - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) else false and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) override __.ProcessNext (input:'T) : bool = if cached.Value.Add input then - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) else false - and Filter<'T,'V> (filter:'T->bool, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) - - override __.ProcessNext (input:'T) : bool = - if filter input then - avoidTailCall (next.ProcessNext input) - else - false - - and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - if filter input then - avoidTailCall (next.ProcessNext (map input)) - else - false - - and Map<'T,'U,'V> (map:'T->'U, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) - - override __.ProcessNext (input:'T) : bool = - avoidTailCall (next.ProcessNext (map input)) - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(next) + inherit SeqComponent<'First,'V>(Upcast.iCompletionChaining next) let input2 = enumerable2.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map override __.ProcessNext (input:'First) : bool = if input2.MoveNext () then - avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) + TailCall.avoid (next.ProcessNext (map'.Invoke (input, input2.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -352,14 +291,14 @@ namespace Microsoft.FSharp.Collections input2.Dispose () and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'Second,'V>(next) + inherit SeqComponent<'Second,'V>(Upcast.iCompletionChaining next) let input1 = enumerable1.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map override __.ProcessNext (input:'Second) : bool = if input1.MoveNext () then - avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) + TailCall.avoid (next.ProcessNext (map'.Invoke (input1.Current, input))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -368,7 +307,7 @@ namespace Microsoft.FSharp.Collections input1.Dispose () and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(next) + inherit SeqComponent<'First,'V>(Upcast.iCompletionChaining next) let input2 = enumerable2.GetEnumerator () let input3 = enumerable3.GetEnumerator () @@ -376,7 +315,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'First) : bool = if input2.MoveNext () && input3.MoveNext () then - avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) + TailCall.avoid (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -385,28 +324,8 @@ namespace Microsoft.FSharp.Collections try input2.Dispose () finally input3.Dispose () - and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - let u = map input - if filter u then - avoidTailCall (next.ProcessNext u) - else - false - - and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable idx = 0 - let mapi' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt mapi - - override __.ProcessNext (input:'T) : bool = - idx <- idx + 1 - avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) - and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(next) + inherit SeqComponent<'First,'V>(Upcast.iCompletionChaining next) let mutable idx = 0 let input2 = enumerable2.GetEnumerator () @@ -415,7 +334,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'First) : bool = if input2.MoveNext () then idx <- idx + 1 - avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) + TailCall.avoid (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -424,7 +343,7 @@ namespace Microsoft.FSharp.Collections input2.Dispose () and Pairwise<'T,'V> (next:Consumer<'T*'T,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let mutable isFirst = true let mutable lastValue = Unchecked.defaultof<'T> @@ -437,45 +356,46 @@ namespace Microsoft.FSharp.Collections else let currentPair = lastValue, input lastValue <- input - avoidTailCall (next.ProcessNext currentPair) + TailCall.avoid (next.ProcessNext currentPair) and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:Consumer<'State,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let mutable foldResult = initialState override __.ProcessNext (input:'T) : bool = foldResult <- f.Invoke(foldResult, input) - avoidTailCall (next.ProcessNext foldResult) + TailCall.avoid (next.ProcessNext foldResult) - and Skip<'T,'V> (skipCount:int, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Skip<'T,'V> (skipCount:int, notEnoughElements:string->array->unit, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let mutable count = 0 - override __.Skipping () = - if count < skipCount then - count <- count + 1 - true - else - false + interface ISkipping with + member __.Skipping () = + if count < skipCount then + count <- count + 1 + true + else + false override __.ProcessNext (input:'T) : bool = if count < skipCount then count <- count + 1 false else - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) override __.OnComplete _ = if count < skipCount then let x = skipCount - count - invalidOpFmt "tried to skip {0} {1} past the end of the seq" + notEnoughElements "{0}\ntried to skip {1} {2} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] and SkipWhile<'T,'V> (predicate:'T->bool, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let mutable skip = true @@ -485,9 +405,9 @@ namespace Microsoft.FSharp.Collections if skip then false else - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) else - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) and Take<'T,'V> (takeCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipelineIdx:int) = inherit Truncate<'T, 'V>(takeCount, outOfBand, next, pipelineIdx) @@ -499,17 +419,17 @@ namespace Microsoft.FSharp.Collections [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] and TakeWhile<'T,'V> (predicate:'T->bool, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) override __.ProcessNext (input:'T) : bool = if predicate input then - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) else outOfBand.StopFurtherProcessing pipeIdx false and Tail<'T, 'V> (next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let mutable first = true @@ -518,14 +438,14 @@ namespace Microsoft.FSharp.Collections first <- false false else - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) override this.OnComplete _ = if first then invalidArg "source" (SR.GetString(SR.notEnoughElements)) and Truncate<'T,'V> (truncateCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let mutable count = 0 @@ -536,13 +456,13 @@ namespace Microsoft.FSharp.Collections count <- count + 1 if count = truncateCount then outOfBand.StopFurtherProcessing pipeIdx - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) else outOfBand.StopFurtherProcessing pipeIdx false and Windowed<'T,'V> (windowSize: int, next:Consumer<'T[],'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let circularBuffer = Array.zeroCreateUnchecked windowSize let mutable idx = 0 @@ -562,12 +482,12 @@ namespace Microsoft.FSharp.Collections else if windowSize < 32 then let window = Array.init windowSize (fun i -> circularBuffer.[(idx+i) % windowSize]) - avoidTailCall (next.ProcessNext window) + TailCall.avoid (next.ProcessNext window) else let window = Array.zeroCreateUnchecked windowSize Array.Copy(circularBuffer, idx, window, 0, windowSize - idx) Array.Copy(circularBuffer, 0, window, windowSize - idx, idx) - avoidTailCall (next.ProcessNext window) + TailCall.avoid (next.ProcessNext window) type SeqProcessNextStates = | InProcess = 0 @@ -629,8 +549,8 @@ namespace Microsoft.FSharp.Collections iterate state let makeIsSkipping (consumer:Consumer<'T,'U>) = - match consumer with - | :? SeqComponent<'T,'U> as c -> c.Skipping + match box consumer with + | :? ISkipping as skip -> skip.Skipping | _ -> fun () -> false let init f (terminatingIdx:int) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = @@ -641,21 +561,23 @@ namespace Microsoft.FSharp.Collections if maybeSkipping then maybeSkipping <- isSkipping () - if (not maybeSkipping) then + if not maybeSkipping then consumer.ProcessNext (f (idx+1)) |> ignore idx <- idx + 1 - let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:ISeqFactory<'T,'U>) executeOn = + let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:SeqFactory<'T,'U>) executeOn = let pipeline = OutOfBand() let result = f (fun () -> (pipeline:>IOutOfBand).StopFurtherProcessing (current.PipeIdx+1)) - let consumer = current.Create pipeline emptyPipeIdx result + let consumer = current.Build pipeline result try executeOn pipeline consumer - (upcastICompletionChaining consumer).OnComplete pipeline.HaltedIdx + let mutable stopTailCall = () + (Upcast.iCompletionChaining consumer).OnComplete (&stopTailCall, pipeline.HaltedIdx) result finally - (upcastICompletionChaining consumer).OnDispose () + let mutable stopTailCall = () + (Upcast.iCompletionChaining consumer).OnDispose (&stopTailCall) module Enumerable = type Empty<'T>() = @@ -677,10 +599,11 @@ namespace Microsoft.FSharp.Collections type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ICompletionChaining) = interface IDisposable with member __.Dispose() : unit = - seqComponent.OnDispose () + let mutable stopTailCall = () + seqComponent.OnDispose (&stopTailCall) interface IEnumerator with - member this.Current : obj = box ((upcastEnumerator this)).Current + member this.Current : obj = box ((Upcast.enumerator this)).Current member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)" member __.Reset () : unit = noReset () @@ -699,13 +622,13 @@ namespace Microsoft.FSharp.Collections abstract member Append : (seq<'T>) -> IEnumerable<'T> - default this.Append source = upcastEnumerable (AppendEnumerable [this; source]) + default this.Append source = Upcast.enumerable (AppendEnumerable [this; source]) interface IEnumerable with member this.GetEnumerator () : IEnumerator = - let genericEnumerable = upcastEnumerable this + let genericEnumerable = Upcast.enumerable this let genericEnumerator = genericEnumerable.GetEnumerator () - upcastEnumeratorNonGeneric genericEnumerator + Upcast.enumeratorNonGeneric genericEnumerator interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement () @@ -725,7 +648,8 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + let mutable stopTailCall = () + (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -738,19 +662,20 @@ namespace Microsoft.FSharp.Collections try source.Dispose () finally - (upcastICompletionChaining seqComponent).OnDispose () + let mutable stopTailCall = () + (Upcast.iCompletionChaining seqComponent).OnDispose (&stopTailCall) - and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:ISeqFactory<'T,'U>) = + and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqFactory<'T,'U>) = inherit EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Build result (SetResult<'U> result), result)) interface ISeq<'U> with - member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) + member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.enumerable enumerable) @@ -782,7 +707,7 @@ namespace Microsoft.FSharp.Collections | _ -> failwith "library implementation error: all states should have been handled" interface IEnumerator with - member this.Current = box ((upcastEnumerator this)).Current + member this.Current = box ((Upcast.enumerator this)).Current member __.MoveNext () = state <- SeqProcessNextStates.InProcess moveNext () @@ -798,14 +723,14 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = - upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) + Upcast.enumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) override this.Append source = - upcastEnumerable (AppendEnumerable (source :: sources)) + Upcast.enumerable (AppendEnumerable (source :: sources)) interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable<'T,'V>(this, next)) + member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) @@ -815,17 +740,17 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = - upcastEnumerator (new ConcatEnumerator<_,_> (sources)) + Upcast.enumerator (new ConcatEnumerator<_,_> (sources)) interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable<'T,'V>(this, next)) + member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) let create enumerable current = - upcastSeq (Enumerable(enumerable, current)) + Upcast.seq (Enumerable(enumerable, current)) module EmptyEnumerable = type Enumerable<'T> () = @@ -838,11 +763,11 @@ namespace Microsoft.FSharp.Collections member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>() override this.Append source = - upcastEnumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) + Upcast.enumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable.Enumerable<'T,'V>(this, next)) + member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable.Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) @@ -873,7 +798,8 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + let mutable stopTailCall = () + (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -881,25 +807,25 @@ namespace Microsoft.FSharp.Collections initMoveNext () moveNext () - type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:ISeqFactory<'T,'U>) = + type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U>(delayedArray, current.Build result (SetResult<'U> result), result)) interface ISeq<'U> with - member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) + member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.array (delayedArray ())) - let createDelayed (delayedArray:unit->array<'T>) (current:ISeqFactory<'T,'U>) = - upcastSeq (Enumerable(delayedArray, current)) + let createDelayed (delayedArray:unit->array<'T>) (current:SeqFactory<'T,'U>) = + Upcast.seq (Enumerable(delayedArray, current)) - let create (array:array<'T>) (current:ISeqFactory<'T,'U>) = + let create (array:array<'T>) (current:SeqFactory<'T,'U>) = createDelayed (fun () -> array) current let createDelayedId (delayedArray:unit -> array<'T>) = @@ -924,7 +850,8 @@ namespace Microsoft.FSharp.Collections moveNext tail | _ -> result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + let mutable stopTailCall = () + (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -932,23 +859,23 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext list - type Enumerable<'T,'U>(alist:list<'T>, current:ISeqFactory<'T,'U>) = + type Enumerable<'T,'U>(alist:list<'T>, current:SeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U>(alist, current.Build result (SetResult<'U> result), result)) interface ISeq<'U> with - member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) + member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.list alist) let create alist current = - upcastSeq (Enumerable(alist, current)) + Upcast.seq (Enumerable(alist, current)) module Unfold = type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, result:Result<'U>) = @@ -971,17 +898,17 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext () - type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:ISeqFactory<'T,'U>) = + type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Build result (SetResult<'U> result), result)) interface ISeq<'U> with - member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + member this.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.unfold generator state) @@ -1037,7 +964,8 @@ namespace Microsoft.FSharp.Collections raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) else result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + let mutable stopTailCall = () + (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -1045,17 +973,17 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext () - type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:ISeqFactory<'T,'U>) = + type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U>(count, f, current.Build result (SetResult<'U> result), result)) interface ISeq<'U> with - member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + member this.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) member this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = let terminatingIdx = getTerminatingIdx count @@ -1122,25 +1050,25 @@ namespace Microsoft.FSharp.Collections upto (if count.HasValue then Some (count.Value-1) else None) f interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable<'T,'V>(count, f, next)) + member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable<'T,'V>(count, f, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (upcastEnumerable this)) + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (Upcast.enumerable this)) [] let toComposer (source:seq<'T>) : ISeq<'T> = - checkNonNull "source" source match source with | :? ISeq<'T> as s -> s - | :? array<'T> as a -> upcastSeq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) - | :? list<'T> as a -> upcastSeq (List.Enumerable(a, IdentityFactory.Instance)) - | _ -> upcastSeq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) + | :? array<'T> as a -> Upcast.seq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) + | :? list<'T> as a -> Upcast.seq (List.Enumerable(a, IdentityFactory.Instance)) + | null -> nullArg "source" + | _ -> Upcast.seq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) let inline foreach f (source:ISeq<_>) = source.ForEach f - let inline compose factory (source:ISeq<'T>) = + let inline compose (factory:#SeqFactory<_,_>) (source:ISeq<'T>) = source.Compose factory [] @@ -1148,17 +1076,17 @@ namespace Microsoft.FSharp.Collections [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> = - upcastSeq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) + Upcast.seq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) [] let initInfinite<'T> (f:int->'T) : ISeq<'T> = - upcastSeq (new Init.EnumerableDecider<'T>(Nullable (), f)) + Upcast.seq (new Init.EnumerableDecider<'T>(Nullable (), f)) [] let init<'T> (count:int) (f:int->'T) : ISeq<'T> = if count < 0 then invalidArgInputMustBeNonNegative "count" count elif count = 0 then empty else - upcastSeq (new Init.EnumerableDecider<'T>(Nullable count, f)) + Upcast.seq (new Init.EnumerableDecider<'T>(Nullable count, f)) [] let iter f (source:ISeq<'T>) = @@ -1170,20 +1098,22 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> ignore - [] - let tryItem i (source:ISeq<'T>) = - if i < 0 then None else - source + [] + let tryHead (source:ISeq<'T>) = + source |> foreach (fun halt -> - { new Folder<'T, Values>> (Values<_,_> (0, None)) with + { new Folder<'T, Option<'T>> (None) with override this.ProcessNext value = - if this.Value._1 = i then - this.Value._2 <- Some value - halt () - else - this.Value._1 <- this.Value._1 + 1 + this.Value <- Some value + halt () Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun item -> item.Value._2 + |> fun head -> head.Value + + [] + let tryItem i (source:ISeq<'T>) = + if i < 0 then None else + source.Compose (SkipFactory(i, fun _ _ -> ())) + |> tryHead [] let iteri f (source:ISeq<'T>) = @@ -1233,21 +1163,40 @@ namespace Microsoft.FSharp.Collections halt () Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun forall -> forall.Value - + [] - let filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = - source - |> compose (FilterFactory f) + let inline filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { new SeqComponentSimple<'T,'V>(Upcast.iCompletionChaining next) with + member __.ProcessNext input = + if f input then TailCall.avoid (next.ProcessNext input) + else false } } [] - let map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = - source - |> compose (MapFactory f) + let inline map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = + source |> compose { new SeqFactory<'T,'U>() with + member __.Create _ _ next = + upcast { new SeqComponentSimple<'T,'V>(Upcast.iCompletionChaining next) with + member __.ProcessNext input = + TailCall.avoid (next.ProcessNext (f input)) } } [] - let mapi f source = - source - |> compose (MapiFactory f) + let inline mapi f source = + source |> compose { new SeqFactory<'T,'U>() with + member __.Create _ _ next = + upcast { new SeqComponentSimpleValue<'T,'V,int>(Upcast.iCompletionChaining next, -1) with + override this.ProcessNext (input:'T) : bool = + this.Value <- this.Value + 1 + TailCall.avoid (next.ProcessNext (f this.Value input)) } } + + let mapi_adapt (f:OptimizedClosures.FSharpFunc<_,_,_>) source = + source |> compose { new SeqFactory<'T,'U>() with + member __.Create _ _ next = + upcast { new SeqComponentSimpleValue<'T,'V,int>(Upcast.iCompletionChaining next, -1) with + override this.ProcessNext (input:'T) : bool = + this.Value <- this.Value + 1 + TailCall.avoid (next.ProcessNext (f.Invoke (this.Value, input))) } } [] let choose f source = @@ -1255,9 +1204,8 @@ namespace Microsoft.FSharp.Collections |> compose (ChooseFactory f) [] - let indexed source = - source - |> compose (MapiFactory (fun i x -> i,x)) + let inline indexed source = + mapi (fun i x -> i,x) source [] let tryPick f (source:ISeq<'T>) = diff --git a/src/fsharp/FSharp.Core/seqcomposer.fsi b/src/fsharp/FSharp.Core/seqcomposer.fsi index 838cee6da37..c9bdf2fdb3e 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fsi +++ b/src/fsharp/FSharp.Core/seqcomposer.fsi @@ -14,7 +14,6 @@ namespace Microsoft.FSharp.Collections /// PipeIdx denotes the index of the element within the pipeline. 0 denotes the /// source of the chain. type PipeIdx = int - type ``PipeIdx?`` = Nullable /// ICompletionChaining is used to correctly handle cleaning up of the pipeline. A /// base implementation is provided in Consumer, and should not be overwritten. Consumer @@ -26,10 +25,10 @@ namespace Microsoft.FSharp.Collections /// operation which didn't have a source at least as large as was required). It is /// not called in the case of an exception being thrown whilst the stream is still /// being processed. - abstract OnComplete : PipeIdx -> unit + abstract OnComplete : stopTailCall:byref*PipeIdx -> unit /// OnDispose is used to cleanup the stream. It is always called at the last operation /// after the enumeration has completed. - abstract OnDispose : unit -> unit + abstract OnDispose : stopTailCall:byref -> unit type IOutOfBand = abstract StopFurtherProcessing : PipeIdx -> unit @@ -71,204 +70,160 @@ namespace Microsoft.FSharp.Collections new : init:'U -> Folder<'T,'U> val mutable Value: 'U - type ISeqFactory<'T,'U> = - abstract member Create : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> - abstract member PipeIdx : PipeIdx + [] + type SeqFactory<'T,'U> = + new : unit -> SeqFactory<'T,'U> + abstract PipeIdx : PipeIdx + abstract member Create : IOutOfBand -> PipeIdx -> Consumer<'U,'V> -> Consumer<'T,'V> type ISeq<'T> = inherit System.Collections.Generic.IEnumerable<'T> - abstract member Compose : ISeqFactory<'T,'U> -> ISeq<'U> + abstract member Compose : SeqFactory<'T,'U> -> ISeq<'U> abstract member ForEach : f:((unit -> unit) -> 'a) -> 'a when 'a :> Consumer<'T,'T> open Core - module internal Helpers = - val inline avoidTailCall : boolean:bool -> bool - val inline upcastSeq : t: #ISeq<'T> -> ISeq<'T> - val inline upcastFactory : - t: #ISeqFactory<'T,'U> -> ISeqFactory<'T,'U> - val inline upcastEnumerable : t:#IEnumerable<'T> -> IEnumerable<'T> - val inline upcastEnumerator : t:#IEnumerator<'T> ->IEnumerator<'T> - val inline upcastEnumeratorNonGeneric : - t:#IEnumerator -> IEnumerator - val inline upcastICompletionChaining : - t: #ICompletionChaining -> ICompletionChaining - module internal Seq = - [] - type SeqComponentFactory<'T,'U> = + type ComposedFactory<'T,'U,'V> = class - interface ISeqFactory<'T,'U> - new : unit -> SeqComponentFactory<'T,'U> - new : pipeIdx: ``PipeIdx?`` -> - SeqComponentFactory<'T,'U> - end - and ComposedFactory<'T,'U,'V> = - class - inherit SeqComponentFactory<'T,'V> - interface ISeqFactory<'T,'V> - private new : first: ISeqFactory<'T,'U> * - second: ISeqFactory<'U,'V> * + inherit SeqFactory<'T,'V> + private new : first: SeqFactory<'T,'U> * + second: SeqFactory<'U,'V> * secondPipeIdx: PipeIdx -> ComposedFactory<'T,'U,'V> static member - Combine : first: ISeqFactory<'T,'U> -> - second: ISeqFactory<'U,'V> -> - ISeqFactory<'T,'V> + Combine : first: SeqFactory<'T,'U> -> + second: SeqFactory<'U,'V> -> + SeqFactory<'T,'V> end and ChooseFactory<'T,'U> = class - inherit SeqComponentFactory<'T,'U> - interface ISeqFactory<'T,'U> + inherit SeqFactory<'T,'U> new : filter:('T -> 'U option) -> ChooseFactory<'T,'U> end and DistinctFactory<'T when 'T : equality> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : unit -> DistinctFactory<'T> end and DistinctByFactory<'T,'Key when 'Key : equality> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : keyFunction:('T -> 'Key) -> DistinctByFactory<'T,'Key> end and ExceptFactory<'T when 'T : equality> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : itemsToExclude:seq<'T> -> ExceptFactory<'T> end - and FilterFactory<'T> = - class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> - new : filter:('T -> bool) -> FilterFactory<'T> - end and IdentityFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : unit -> IdentityFactory<'T> - static member Instance : IdentityFactory<'T> - end - and MapFactory<'T,'U> = - class - inherit SeqComponentFactory<'T,'U> - interface ISeqFactory<'T,'U> - new : map:('T -> 'U) -> MapFactory<'T,'U> + static member Instance : SeqFactory<'T,'T> end and Map2FirstFactory<'First,'Second,'U> = class - inherit SeqComponentFactory<'First,'U> - interface ISeqFactory<'First,'U> + inherit SeqFactory<'First,'U> new : map:('First -> 'Second -> 'U) * input2:IEnumerable<'Second> -> Map2FirstFactory<'First,'Second,'U> end and Map2SecondFactory<'First,'Second,'U> = class - inherit SeqComponentFactory<'Second,'U> - interface ISeqFactory<'Second,'U> + inherit SeqFactory<'Second,'U> new : map:('First -> 'Second -> 'U) * input1:IEnumerable<'First> -> Map2SecondFactory<'First,'Second,'U> end and Map3Factory<'First,'Second,'Third,'U> = class - inherit SeqComponentFactory<'First,'U> - interface ISeqFactory<'First,'U> + inherit SeqFactory<'First,'U> new : map:('First -> 'Second -> 'Third -> 'U) * input2:IEnumerable<'Second> * input3:IEnumerable<'Third> -> Map3Factory<'First,'Second,'Third,'U> end - and MapiFactory<'T,'U> = - class - inherit SeqComponentFactory<'T,'U> - interface ISeqFactory<'T,'U> - new : mapi:(int -> 'T -> 'U) -> MapiFactory<'T,'U> - end and Mapi2Factory<'First,'Second,'U> = class - inherit SeqComponentFactory<'First,'U> - interface ISeqFactory<'First,'U> + inherit SeqFactory<'First,'U> new : map:(int -> 'First -> 'Second -> 'U) * input2:IEnumerable<'Second> -> Mapi2Factory<'First,'Second,'U> end and PairwiseFactory<'T> = class - inherit SeqComponentFactory<'T,('T * 'T)> - interface ISeqFactory<'T,('T * 'T)> + inherit SeqFactory<'T,('T * 'T)> new : unit -> PairwiseFactory<'T> end and ScanFactory<'T,'State> = class - inherit SeqComponentFactory<'T,'State> - interface ISeqFactory<'T,'State> + inherit SeqFactory<'T,'State> new : folder:('State -> 'T -> 'State) * initialState:'State -> ScanFactory<'T,'State> end and SkipFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> - new : count:int -> SkipFactory<'T> + inherit SeqFactory<'T,'T> + new : count:int * notEnoughElements:(string->array->unit) -> SkipFactory<'T> end and SkipWhileFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : predicate:('T -> bool) -> SkipWhileFactory<'T> end and TakeWhileFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : predicate:('T -> bool) -> TakeWhileFactory<'T> end and TakeFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : count:int -> TakeFactory<'T> end and TailFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : unit -> TailFactory<'T> end and TruncateFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : count:int -> TruncateFactory<'T> end and WindowedFactory<'T> = class - inherit SeqComponentFactory<'T,'T []> - interface ISeqFactory<'T,'T []> + inherit SeqFactory<'T,'T []> new : windowSize:int -> WindowedFactory<'T> end + and ISkipping = + interface + abstract member Skipping : unit -> bool + end + + and [] SeqComponentSimple<'T,'U> = + class + inherit Consumer<'T,'U> + interface ICompletionChaining + new : next:ICompletionChaining -> SeqComponentSimple<'T,'U> + end + + and [] SeqComponentSimpleValue<'T,'U,'Value> = + class + inherit SeqComponentSimple<'T,'U> + val mutable Value : 'Value + new : next:ICompletionChaining*value:'Value -> SeqComponentSimpleValue<'T,'U,'Value> + end + and [] SeqComponent<'T,'U> = class - inherit Consumer<'T,'U> - interface ICompletionChaining - new : next: ICompletionChaining -> - SeqComponent<'T,'U> - abstract member - CreateFilter : filter:('T -> bool) -> SeqComponent<'T,'U> - abstract member - CreateMap : map:('S -> 'T) -> SeqComponent<'S,'U> - abstract member Skipping : unit -> bool - override - CreateFilter : filter:('T -> bool) -> SeqComponent<'T,'U> - override CreateMap : map:('S -> 'T) -> SeqComponent<'S,'U> - override Skipping : unit -> bool + inherit Consumer<'T,'U> + interface ICompletionChaining + new : next:ICompletionChaining -> + SeqComponent<'T,'U> end + and Choose<'T,'U,'V> = class inherit SeqComponent<'T,'V> @@ -296,31 +251,6 @@ namespace Microsoft.FSharp.Collections Except<'T,'V> override ProcessNext : input:'T -> bool end - and Filter<'T,'V> = - class - inherit SeqComponent<'T,'V> - new : filter:('T -> bool) * next: Consumer<'T,'V> -> - Filter<'T,'V> - override CreateMap : map:('S -> 'T) -> SeqComponent<'S,'V> - override ProcessNext : input:'T -> bool - end - and FilterThenMap<'T,'U,'V> = - class - inherit SeqComponent<'T,'V> - new : filter:('T -> bool) * map:('T -> 'U) * - next: Consumer<'U,'V> -> - FilterThenMap<'T,'U,'V> - override ProcessNext : input:'T -> bool - end - and Map<'T,'U,'V> = - class - inherit SeqComponent<'T,'V> - new : map:('T -> 'U) * next: Consumer<'U,'V> -> - Map<'T,'U,'V> - override - CreateFilter : filter:('T -> bool) -> SeqComponent<'T,'V> - override ProcessNext : input:'T -> bool - end and Map2First<'First,'Second,'U,'V> = class inherit SeqComponent<'First,'V> @@ -355,21 +285,6 @@ namespace Microsoft.FSharp.Collections override OnDispose : unit -> unit override ProcessNext : input:'First -> bool end - and MapThenFilter<'T,'U,'V> = - class - inherit SeqComponent<'T,'V> - new : map:('T -> 'U) * filter:('U -> bool) * - next: Consumer<'U,'V> -> - MapThenFilter<'T,'U,'V> - override ProcessNext : input:'T -> bool - end - and Mapi<'T,'U,'V> = - class - inherit SeqComponent<'T,'V> - new : mapi:(int -> 'T -> 'U) * next: Consumer<'U,'V> -> - Mapi<'T,'U,'V> - override ProcessNext : input:'T -> bool - end and Mapi2<'First,'Second,'U,'V> = class inherit SeqComponent<'First,'V> @@ -399,11 +314,11 @@ namespace Microsoft.FSharp.Collections and Skip<'T,'V> = class inherit SeqComponent<'T,'V> - new : skipCount:int * next: Consumer<'T,'V> -> + interface ISkipping + new : skipCount:int * exceptionOnNotEnoughElements:(string->array->unit) * next: Consumer<'T,'V> -> Skip<'T,'V> override OnComplete : PipeIdx -> unit override ProcessNext : input:'T -> bool - override Skipping : unit -> bool end and SkipWhile<'T,'V> = class @@ -504,7 +419,7 @@ namespace Microsoft.FSharp.Collections consumer: Consumer<'T,'U> -> unit val execute : f:((unit -> unit) -> 'a) -> - current: ISeqFactory<'T,'U> -> + current: SeqFactory<'T,'U> -> executeOn:( OutOfBand -> Consumer<'T,'U> -> unit) -> 'a when 'a :> Consumer<'U,'U> end @@ -558,7 +473,7 @@ namespace Microsoft.FSharp.Collections interface ISeq<'U> interface IEnumerable<'U> new : enumerable:IEnumerable<'T> * - current: ISeqFactory<'T,'U> -> + current: SeqFactory<'T,'U> -> Enumerable<'T,'U> end and ConcatEnumerator<'T,'Collection when 'Collection :> seq<'T>> = @@ -589,7 +504,7 @@ namespace Microsoft.FSharp.Collections end val create : enumerable:IEnumerable<'a> -> - current: ISeqFactory<'a,'b> -> ISeq<'b> + current: SeqFactory<'a,'b> -> ISeq<'b> end module EmptyEnumerable = begin type Enumerable<'T> = @@ -618,15 +533,15 @@ namespace Microsoft.FSharp.Collections interface ISeq<'U> interface IEnumerable<'U> new : delayedArray:(unit -> 'T array) * - current: ISeqFactory<'T,'U> -> + current: SeqFactory<'T,'U> -> Enumerable<'T,'U> end val createDelayed : delayedArray:(unit -> 'T array) -> - current: ISeqFactory<'T,'U> -> ISeq<'U> + current: SeqFactory<'T,'U> -> ISeq<'U> val create : array:'T array -> - current: ISeqFactory<'T,'U> -> ISeq<'U> + current: SeqFactory<'T,'U> -> ISeq<'U> val createDelayedId : delayedArray:(unit -> 'T array) -> ISeq<'T> val createId : array:'T array -> ISeq<'T> @@ -644,12 +559,12 @@ namespace Microsoft.FSharp.Collections inherit Enumerable.EnumerableBase<'U> interface ISeq<'U> interface IEnumerable<'U> - new : alist:'T list * current: ISeqFactory<'T,'U> -> + new : alist:'T list * current: SeqFactory<'T,'U> -> Enumerable<'T,'U> end val create : alist:'a list -> - current: ISeqFactory<'a,'b> -> ISeq<'b> + current: SeqFactory<'a,'b> -> ISeq<'b> end module Unfold = begin type Enumerator<'T,'U,'State> = @@ -667,7 +582,7 @@ namespace Microsoft.FSharp.Collections interface ISeq<'U> interface IEnumerable<'U> new : generator:('GeneratorState -> ('T * 'GeneratorState) option) * - state:'GeneratorState * current: ISeqFactory<'T,'U> -> + state:'GeneratorState * current: SeqFactory<'T,'U> -> Enumerable<'T,'U,'GeneratorState> end end @@ -687,7 +602,7 @@ namespace Microsoft.FSharp.Collections interface ISeq<'U> interface IEnumerable<'U> new : count:Nullable * f:(int -> 'T) * - current: ISeqFactory<'T,'U> -> + current: SeqFactory<'T,'U> -> Enumerable<'T,'U> end val upto : @@ -707,9 +622,6 @@ namespace Microsoft.FSharp.Collections val inline foreach : f:((unit -> unit) -> 'a) -> source: ISeq<'b> -> 'a when 'a :> Consumer<'b,'b> - val inline compose : - factory: ISeqFactory<'T,'a> -> - source: ISeq<'T> -> ISeq<'a> [] val empty<'T> : ISeq<'T> [] @@ -722,6 +634,8 @@ namespace Microsoft.FSharp.Collections val init : count:int -> f:(int -> 'T) -> ISeq<'T> [] val iter : f:('T -> unit) -> source: ISeq<'T> -> unit + [] + val tryHead : source: ISeq<'T> -> 'T option [] val tryItem : i:int -> source: ISeq<'T> -> 'T option [] @@ -733,22 +647,24 @@ namespace Microsoft.FSharp.Collections element:'T -> source: ISeq<'T> -> bool when 'T : equality [] val forall : f:('T -> bool) -> source: ISeq<'T> -> bool - [] - val filter : - f:('T -> bool) -> source: ISeq<'T> -> ISeq<'T> - [] - val map : - f:('T -> 'U) -> source: ISeq<'T> -> ISeq<'U> + + [] + val inline filter : f:('T -> bool) -> source: ISeq<'T> -> ISeq<'T> + + [] + val inline map : f:('T -> 'U) -> source: ISeq<'T> -> ISeq<'U> + [] - val mapi : - f:(int -> 'a -> 'b) -> - source: ISeq<'a> -> ISeq<'b> + val inline mapi : f:(int->'a->'b) -> source: ISeq<'a> -> ISeq<'b> + + val mapi_adapt : f:OptimizedClosures.FSharpFunc -> source: ISeq<'a> -> ISeq<'b> + [] - val choose : - f:('a -> 'b option) -> - source: ISeq<'a> -> ISeq<'b> + val choose : f:('a->option<'b>) -> source: ISeq<'a> -> ISeq<'b> + [] - val indexed : source: ISeq<'a> -> ISeq + val inline indexed : source: ISeq<'a> -> ISeq + [] val tryPick : f:('T -> 'U option) -> source: ISeq<'T> -> Option<'U> diff --git a/tests/fsharpqa/Source/CodeGen/EmittedIL/QueryExpressionStepping/Linq101Aggregates01.il.netfx4.bsl b/tests/fsharpqa/Source/CodeGen/EmittedIL/QueryExpressionStepping/Linq101Aggregates01.il.netfx4.bsl index 97e240269b4..9f4b80a6edf 100644 --- a/tests/fsharpqa/Source/CodeGen/EmittedIL/QueryExpressionStepping/Linq101Aggregates01.il.netfx4.bsl +++ b/tests/fsharpqa/Source/CodeGen/EmittedIL/QueryExpressionStepping/Linq101Aggregates01.il.netfx4.bsl @@ -38,20 +38,20 @@ } .mresource public FSharpSignatureData.Linq101Aggregates01 { - // Offset: 0x00000000 Length: 0x0000060C + // Offset: 0x00000000 Length: 0x000005FA } .mresource public FSharpOptimizationData.Linq101Aggregates01 { - // Offset: 0x00000610 Length: 0x00000211 + // Offset: 0x00000600 Length: 0x00000211 } .module Linq101Aggregates01.exe -// MVID: {58067926-D281-4783-A745-038326790658} +// MVID: {581D1D27-D281-4783-A745-0383271D1D58} .imagebase 0x00400000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x00AC0000 +// Image base: 0x02BA0000 // =============== CLASS MEMBERS DECLARATION =================== @@ -116,7 +116,7 @@ // Code size 196 (0xc4) .maxstack 6 .language '{AB4F38C9-B6E6-43BA-BE3B-58080B2CCCE3}', '{994B45C4-E6E9-11D2-903F-00C04FA302A1}', '{5A869D0B-6611-11D3-BD2A-0000F80849BD}' - .line 100001,100001 : 0,0 'C:\\GitHub\\dsyme\\visualfsharp\\tests\\fsharpqa\\Source\\CodeGen\\EmittedIL\\QueryExpressionStepping\\Linq101Aggregates01.fs' + .line 100001,100001 : 0,0 'C:\\src\\visualfsharp\\tests\\fsharpqa\\Source\\CodeGen\\EmittedIL\\QueryExpressionStepping\\Linq101Aggregates01.fs' IL_0000: ldarg.0 IL_0001: ldfld int32 Linq101Aggregates01/uniqueFactors@12::pc IL_0006: ldc.i4.1 @@ -823,6 +823,90 @@ } // end of class 'numSum@22-1' + .class auto autochar serializable sealed nested assembly beforefieldinit specialname 'numSum@22-3' + extends class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2 + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 06 00 00 00 00 00 ) + .field public class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 f + .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) + .method public specialname rtspecialname + instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 f) cil managed + { + // Code size 18 (0x12) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 Linq101Aggregates01/'numSum@22-3'::f + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldc.i4.0 + IL_000a: callvirt instance void class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2::.ctor(!1) + IL_000f: ldarg.0 + IL_0010: pop + IL_0011: ret + } // end of method 'numSum@22-3'::.ctor + + .method public hidebysig virtual instance bool + ProcessNext(int32 input) cil managed + { + // Code size 28 (0x1c) + .maxstack 8 + .line 22,22 : 9,16 '' + IL_0000: ldarg.0 + IL_0001: ldarg.0 + IL_0002: ldfld !1 class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2::Value + IL_0007: ldarg.0 + IL_0008: ldfld class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 Linq101Aggregates01/'numSum@22-3'::f + IL_000d: ldarg.1 + IL_000e: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) + IL_0013: add.ovf + IL_0014: stfld !1 class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2::Value + IL_0019: nop + IL_001a: ldc.i4.0 + IL_001b: ret + } // end of method 'numSum@22-3'::ProcessNext + + } // end of class 'numSum@22-3' + + .class auto ansi serializable nested assembly beforefieldinit 'numSum@22-2' + extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2> + { + .field public class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 f + .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) + .method assembly specialname rtspecialname + instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 f) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2>::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 Linq101Aggregates01/'numSum@22-2'::f + IL_000d: ret + } // end of method 'numSum@22-2'::.ctor + + .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2 + Invoke(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 _arg1) cil managed + { + // Code size 13 (0xd) + .maxstack 8 + .line 22,22 : 9,16 '' + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldfld class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 Linq101Aggregates01/'numSum@22-2'::f + IL_0007: newobj instance void Linq101Aggregates01/'numSum@22-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) + IL_000c: ret + } // end of method 'numSum@22-2'::Invoke + + } // end of class 'numSum@22-2' + .class auto autochar serializable sealed nested assembly beforefieldinit specialname totalChars@30 extends class [FSharp.Core]Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase`1 { @@ -1219,6 +1303,90 @@ } // end of class 'totalChars@31-1' + .class auto autochar serializable sealed nested assembly beforefieldinit specialname 'totalChars@31-3' + extends class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2 + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 06 00 00 00 00 00 ) + .field public class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 f + .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) + .method public specialname rtspecialname + instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 f) cil managed + { + // Code size 18 (0x12) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 Linq101Aggregates01/'totalChars@31-3'::f + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldc.i4.0 + IL_000a: callvirt instance void class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2::.ctor(!1) + IL_000f: ldarg.0 + IL_0010: pop + IL_0011: ret + } // end of method 'totalChars@31-3'::.ctor + + .method public hidebysig virtual instance bool + ProcessNext(string input) cil managed + { + // Code size 28 (0x1c) + .maxstack 8 + .line 31,31 : 9,25 '' + IL_0000: ldarg.0 + IL_0001: ldarg.0 + IL_0002: ldfld !1 class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2::Value + IL_0007: ldarg.0 + IL_0008: ldfld class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 Linq101Aggregates01/'totalChars@31-3'::f + IL_000d: ldarg.1 + IL_000e: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) + IL_0013: add.ovf + IL_0014: stfld !1 class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2::Value + IL_0019: nop + IL_001a: ldc.i4.0 + IL_001b: ret + } // end of method 'totalChars@31-3'::ProcessNext + + } // end of class 'totalChars@31-3' + + .class auto ansi serializable nested assembly beforefieldinit 'totalChars@31-2' + extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2> + { + .field public class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 f + .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) + .method assembly specialname rtspecialname + instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 f) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2>::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 Linq101Aggregates01/'totalChars@31-2'::f + IL_000d: ret + } // end of method 'totalChars@31-2'::.ctor + + .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2 + Invoke(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 _arg1) cil managed + { + // Code size 13 (0xd) + .maxstack 8 + .line 31,31 : 9,25 '' + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldfld class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 Linq101Aggregates01/'totalChars@31-2'::f + IL_0007: newobj instance void Linq101Aggregates01/'totalChars@31-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) + IL_000c: ret + } // end of method 'totalChars@31-2'::Invoke + + } // end of class 'totalChars@31-2' + .class auto ansi serializable nested assembly beforefieldinit categories@39 extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2> { @@ -1723,6 +1891,90 @@ } // end of class 'sum@43-1' + .class auto autochar serializable sealed nested assembly beforefieldinit specialname 'sum@43-3' + extends class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2 + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 06 00 00 00 00 00 ) + .field public class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 f + .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) + .method public specialname rtspecialname + instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 f) cil managed + { + // Code size 18 (0x12) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 Linq101Aggregates01/'sum@43-3'::f + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldc.i4.0 + IL_000a: callvirt instance void class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2::.ctor(!1) + IL_000f: ldarg.0 + IL_0010: pop + IL_0011: ret + } // end of method 'sum@43-3'::.ctor + + .method public hidebysig virtual instance bool + ProcessNext(class [Utils]Utils/Product input) cil managed + { + // Code size 28 (0x1c) + .maxstack 8 + .line 43,43 : 13,33 '' + IL_0000: ldarg.0 + IL_0001: ldarg.0 + IL_0002: ldfld !1 class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2::Value + IL_0007: ldarg.0 + IL_0008: ldfld class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 Linq101Aggregates01/'sum@43-3'::f + IL_000d: ldarg.1 + IL_000e: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) + IL_0013: add.ovf + IL_0014: stfld !1 class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2::Value + IL_0019: nop + IL_001a: ldc.i4.0 + IL_001b: ret + } // end of method 'sum@43-3'::ProcessNext + + } // end of class 'sum@43-3' + + .class auto ansi serializable nested assembly beforefieldinit 'sum@43-2' + extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2> + { + .field public class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 f + .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) + .method assembly specialname rtspecialname + instance void .ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 f) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) + // Code size 14 (0xe) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2>::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 Linq101Aggregates01/'sum@43-2'::f + IL_000d: ret + } // end of method 'sum@43-2'::.ctor + + .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2 + Invoke(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 _arg1) cil managed + { + // Code size 13 (0xd) + .maxstack 8 + .line 43,43 : 13,33 '' + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldfld class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 Linq101Aggregates01/'sum@43-2'::f + IL_0007: newobj instance void Linq101Aggregates01/'sum@43-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) + IL_000c: ret + } // end of method 'sum@43-2'::Invoke + + } // end of class 'sum@43-2' + .class auto ansi serializable nested assembly beforefieldinit 'categories@40-3' extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,int32>,object>> { @@ -1745,7 +1997,7 @@ .method public strict virtual instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,int32>,object> Invoke(class [System.Core]System.Linq.IGrouping`2 _arg2) cil managed { - // Code size 169 (0xa9) + // Code size 116 (0x74) .maxstack 10 .locals init ([0] class [System.Core]System.Linq.IGrouping`2 g, [1] int32 sum, @@ -1755,10 +2007,7 @@ [5] class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 V_5, [6] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 V_6, [7] class [mscorlib]System.Collections.Generic.IEnumerable`1 V_7, - [8] class [mscorlib]System.Collections.Generic.IEnumerator`1 V_8, - [9] int32 V_9, - [10] int32 V_10, - [11] class [mscorlib]System.IDisposable V_11) + [8] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2> V_8) .line 40,40 : 38,39 '' IL_0000: nop IL_0001: ldarg.1 @@ -1793,70 +2042,25 @@ IL_0039: ldloc.s V_5 IL_003b: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::get_Source() IL_0040: stloc.s V_7 - IL_0042: ldloc.s V_7 - IL_0044: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1::GetEnumerator() + IL_0042: ldloc.s V_6 + IL_0044: newobj instance void Linq101Aggregates01/'sum@43-2'::.ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) IL_0049: stloc.s V_8 - .try - { - IL_004b: ldc.i4.0 - IL_004c: stloc.s V_10 - IL_004e: ldloc.s V_8 - IL_0050: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() - IL_0055: brfalse.s IL_006d - - .line 43,43 : 13,33 '' - IL_0057: ldloc.s V_10 - IL_0059: ldloc.s V_6 - IL_005b: ldloc.s V_8 - IL_005d: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1::get_Current() - IL_0062: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) - IL_0067: add.ovf - IL_0068: stloc.s V_10 - .line 100001,100001 : 0,0 '' - IL_006a: nop - IL_006b: br.s IL_004e - - IL_006d: ldloc.s V_10 - IL_006f: stloc.s V_9 - IL_0071: leave.s IL_0091 - - } // end .try - finally - { - IL_0073: ldloc.s V_8 - IL_0075: isinst [mscorlib]System.IDisposable - IL_007a: stloc.s V_11 - IL_007c: ldloc.s V_11 - IL_007e: brfalse.s IL_0082 - - IL_0080: br.s IL_0084 - - IL_0082: br.s IL_008e - - .line 100001,100001 : 0,0 '' - IL_0084: ldloc.s V_11 - IL_0086: callvirt instance void [mscorlib]System.IDisposable::Dispose() - IL_008b: ldnull - IL_008c: pop - IL_008d: endfinally - .line 100001,100001 : 0,0 '' - IL_008e: ldnull - IL_008f: pop - IL_0090: endfinally - .line 100001,100001 : 0,0 '' - } // end handler - IL_0091: ldloc.s V_9 - IL_0093: stloc.1 + IL_004b: ldloc.s V_7 + IL_004d: call class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/ISeq`1 [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToComposer(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_0052: ldloc.s V_8 + IL_0054: callvirt instance !!0 class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/ISeq`1::ForEach>(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!0>) + IL_0059: ldfld !1 class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2::Value + IL_005e: stloc.1 .line 45,45 : 9,28 '' - IL_0094: ldarg.0 - IL_0095: ldfld class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder Linq101Aggregates01/'categories@40-3'::builder@ - IL_009a: ldloc.0 - IL_009b: ldloc.1 - IL_009c: newobj instance void class [mscorlib]System.Tuple`2,int32>::.ctor(!0, + IL_005f: ldarg.0 + IL_0060: ldfld class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder Linq101Aggregates01/'categories@40-3'::builder@ + IL_0065: ldloc.0 + IL_0066: ldloc.1 + IL_0067: newobj instance void class [mscorlib]System.Tuple`2,int32>::.ctor(!0, !1) - IL_00a1: tail. - IL_00a3: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Yield,int32>,object>(!!0) - IL_00a8: ret + IL_006c: tail. + IL_006e: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Yield,int32>,object>(!!0) + IL_0073: ret } // end of method 'categories@40-3'::Invoke } // end of class 'categories@40-3' @@ -7987,7 +8191,7 @@ .method public static void main@() cil managed { .entrypoint - // Code size 1965 (0x7ad) + // Code size 1859 (0x743) .maxstack 13 .locals init ([0] class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 factorsOf300, [1] int32 uniqueFactors, @@ -8016,56 +8220,50 @@ [24] class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 V_24, [25] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 V_25, [26] class [mscorlib]System.Collections.Generic.IEnumerable`1 V_26, - [27] class [mscorlib]System.Collections.Generic.IEnumerator`1 V_27, - [28] int32 V_28, - [29] int32 V_29, - [30] class [mscorlib]System.IDisposable V_30, - [31] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_31, - [32] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_32, - [33] class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2> V_33, - [34] class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 V_34, - [35] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 V_35, - [36] class [mscorlib]System.Collections.Generic.IEnumerable`1 V_36, - [37] class [mscorlib]System.Collections.Generic.IEnumerator`1 V_37, - [38] int32 V_38, - [39] int32 V_39, - [40] class [mscorlib]System.IDisposable V_40, + [27] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2> V_27, + [28] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_28, + [29] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_29, + [30] class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2> V_30, + [31] class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 V_31, + [32] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 V_32, + [33] class [mscorlib]System.Collections.Generic.IEnumerable`1 V_33, + [34] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2> V_34, + [35] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_35, + [36] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_36, + [37] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_37, + [38] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_38, + [39] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_39, + [40] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_40, [41] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_41, [42] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_42, [43] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_43, [44] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_44, [45] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_45, - [46] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_46, - [47] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_47, - [48] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_48, - [49] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_49, - [50] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_50, - [51] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_51, - [52] class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2> V_52, - [53] class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 V_53, - [54] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 V_54, - [55] class [mscorlib]System.Collections.Generic.IEnumerable`1 V_55, - [56] class [mscorlib]System.Collections.Generic.IEnumerator`1 V_56, - [57] float64 V_57, - [58] float64 V_58, - [59] int32 V_59, - [60] float64 V_60, - [61] int32 V_61, - [62] class [mscorlib]System.IDisposable V_62, - [63] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_63, - [64] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_64, - [65] class [mscorlib]System.Tuple`2,class [mscorlib]System.Collections.IEnumerable>,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,float64>> V_65, - [66] class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,class [mscorlib]System.Collections.IEnumerable> V_66, - [67] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,float64> V_67, - [68] class [mscorlib]System.Collections.Generic.IEnumerable`1> V_68, - [69] class [mscorlib]System.Collections.Generic.IEnumerator`1> V_69, - [70] float64 V_70, - [71] float64 V_71, - [72] int32 V_72, - [73] float64 V_73, - [74] int32 V_74, - [75] class [mscorlib]System.IDisposable V_75, - [76] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_76) + [46] class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2> V_46, + [47] class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 V_47, + [48] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2 V_48, + [49] class [mscorlib]System.Collections.Generic.IEnumerable`1 V_49, + [50] class [mscorlib]System.Collections.Generic.IEnumerator`1 V_50, + [51] float64 V_51, + [52] float64 V_52, + [53] int32 V_53, + [54] float64 V_54, + [55] int32 V_55, + [56] class [mscorlib]System.IDisposable V_56, + [57] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_57, + [58] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_58, + [59] class [mscorlib]System.Tuple`2,class [mscorlib]System.Collections.IEnumerable>,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,float64>> V_59, + [60] class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,class [mscorlib]System.Collections.IEnumerable> V_60, + [61] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,float64> V_61, + [62] class [mscorlib]System.Collections.Generic.IEnumerable`1> V_62, + [63] class [mscorlib]System.Collections.Generic.IEnumerator`1> V_63, + [64] float64 V_64, + [65] float64 V_65, + [66] int32 V_66, + [67] float64 V_67, + [68] int32 V_68, + [69] class [mscorlib]System.IDisposable V_69, + [70] class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder V_70) .line 8,8 : 1,31 '' IL_0000: nop IL_0001: ldc.i4.2 @@ -8171,739 +8369,649 @@ IL_00da: ldloc.s V_24 IL_00dc: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::get_Source() IL_00e1: stloc.s V_26 - IL_00e3: ldloc.s V_26 - IL_00e5: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1::GetEnumerator() + IL_00e3: ldloc.s V_25 + IL_00e5: newobj instance void Linq101Aggregates01/'numSum@22-2'::.ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) IL_00ea: stloc.s V_27 - .try - { - IL_00ec: ldc.i4.0 - IL_00ed: stloc.s V_29 - IL_00ef: ldloc.s V_27 - IL_00f1: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() - IL_00f6: brfalse.s IL_010e - - .line 22,22 : 9,16 '' - IL_00f8: ldloc.s V_29 - IL_00fa: ldloc.s V_25 - IL_00fc: ldloc.s V_27 - IL_00fe: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1::get_Current() - IL_0103: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) - IL_0108: add.ovf - IL_0109: stloc.s V_29 - .line 100001,100001 : 0,0 '' - IL_010b: nop - IL_010c: br.s IL_00ef - - IL_010e: ldloc.s V_29 - IL_0110: stloc.s V_28 - IL_0112: leave.s IL_0132 - - } // end .try - finally - { - IL_0114: ldloc.s V_27 - IL_0116: isinst [mscorlib]System.IDisposable - IL_011b: stloc.s V_30 - IL_011d: ldloc.s V_30 - IL_011f: brfalse.s IL_0123 - - IL_0121: br.s IL_0125 - - IL_0123: br.s IL_012f - - .line 100001,100001 : 0,0 '' - IL_0125: ldloc.s V_30 - IL_0127: callvirt instance void [mscorlib]System.IDisposable::Dispose() - IL_012c: ldnull - IL_012d: pop - IL_012e: endfinally - .line 100001,100001 : 0,0 '' - IL_012f: ldnull - IL_0130: pop - IL_0131: endfinally - .line 100001,100001 : 0,0 '' - } // end handler - IL_0132: ldloc.s V_28 - IL_0134: dup - IL_0135: stsfld int32 ''.$Linq101Aggregates01::numSum@19 - IL_013a: stloc.3 + IL_00ec: ldloc.s V_26 + IL_00ee: call class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/ISeq`1 [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToComposer(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_00f3: ldloc.s V_27 + IL_00f5: callvirt instance !!0 class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/ISeq`1::ForEach>(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!0>) + IL_00fa: ldfld !1 class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2::Value + IL_00ff: dup + IL_0100: stsfld int32 ''.$Linq101Aggregates01::numSum@19 + IL_0105: stloc.3 .line 26,26 : 1,45 '' - IL_013b: ldstr "cherry" - IL_0140: ldstr "apple" - IL_0145: ldstr "blueberry" - IL_014a: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::get_Empty() - IL_014f: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, + IL_0106: ldstr "cherry" + IL_010b: ldstr "apple" + IL_0110: ldstr "blueberry" + IL_0115: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::get_Empty() + IL_011a: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1) - IL_0154: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, + IL_011f: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1) - IL_0159: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, + IL_0124: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1) - IL_015e: dup - IL_015f: stsfld class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 ''.$Linq101Aggregates01::words@26 - IL_0164: stloc.s words - IL_0166: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() - IL_016b: stloc.s V_31 - IL_016d: ldloc.s V_31 - IL_016f: stloc.s V_32 - IL_0171: ldnull - IL_0172: ldnull - IL_0173: ldnull - IL_0174: ldc.i4.0 - IL_0175: ldnull - IL_0176: newobj instance void Linq101Aggregates01/totalChars@30::.ctor(string, + IL_0129: dup + IL_012a: stsfld class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 ''.$Linq101Aggregates01::words@26 + IL_012f: stloc.s words + IL_0131: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() + IL_0136: stloc.s V_28 + IL_0138: ldloc.s V_28 + IL_013a: stloc.s V_29 + IL_013c: ldnull + IL_013d: ldnull + IL_013e: ldnull + IL_013f: ldc.i4.0 + IL_0140: ldnull + IL_0141: newobj instance void Linq101Aggregates01/totalChars@30::.ctor(string, string, class [mscorlib]System.Collections.Generic.IEnumerator`1, int32, string) - IL_017b: newobj instance void class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_0180: newobj instance void Linq101Aggregates01/'totalChars@31-1'::.ctor() - IL_0185: newobj instance void class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>::.ctor(!0, + IL_0146: newobj instance void class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_014b: newobj instance void Linq101Aggregates01/'totalChars@31-1'::.ctor() + IL_0150: newobj instance void class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>::.ctor(!0, !1) - IL_018a: stloc.s V_33 - IL_018c: ldloc.s V_33 - IL_018e: call instance !0 class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>::get_Item1() - IL_0193: stloc.s V_34 - IL_0195: ldloc.s V_33 - IL_0197: call instance !1 class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>::get_Item2() - IL_019c: stloc.s V_35 - IL_019e: ldloc.s V_34 - IL_01a0: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::get_Source() - IL_01a5: stloc.s V_36 - IL_01a7: ldloc.s V_36 - IL_01a9: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1::GetEnumerator() - IL_01ae: stloc.s V_37 - .try - { - IL_01b0: ldc.i4.0 - IL_01b1: stloc.s V_39 - IL_01b3: ldloc.s V_37 - IL_01b5: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() - IL_01ba: brfalse.s IL_01d2 - - .line 31,31 : 9,25 '' - IL_01bc: ldloc.s V_39 - IL_01be: ldloc.s V_35 - IL_01c0: ldloc.s V_37 - IL_01c2: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1::get_Current() - IL_01c7: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) - IL_01cc: add.ovf - IL_01cd: stloc.s V_39 - .line 100001,100001 : 0,0 '' - IL_01cf: nop - IL_01d0: br.s IL_01b3 - - IL_01d2: ldloc.s V_39 - IL_01d4: stloc.s V_38 - IL_01d6: leave.s IL_01f6 - - } // end .try - finally - { - IL_01d8: ldloc.s V_37 - IL_01da: isinst [mscorlib]System.IDisposable - IL_01df: stloc.s V_40 - IL_01e1: ldloc.s V_40 - IL_01e3: brfalse.s IL_01e7 - - IL_01e5: br.s IL_01e9 - - IL_01e7: br.s IL_01f3 - - .line 100001,100001 : 0,0 '' - IL_01e9: ldloc.s V_40 - IL_01eb: callvirt instance void [mscorlib]System.IDisposable::Dispose() - IL_01f0: ldnull - IL_01f1: pop - IL_01f2: endfinally - .line 100001,100001 : 0,0 '' - IL_01f3: ldnull - IL_01f4: pop - IL_01f5: endfinally - .line 100001,100001 : 0,0 '' - } // end handler - IL_01f6: ldloc.s V_38 - IL_01f8: dup - IL_01f9: stsfld int32 ''.$Linq101Aggregates01::totalChars@28 - IL_01fe: stloc.s totalChars + IL_0155: stloc.s V_30 + IL_0157: ldloc.s V_30 + IL_0159: call instance !0 class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>::get_Item1() + IL_015e: stloc.s V_31 + IL_0160: ldloc.s V_30 + IL_0162: call instance !1 class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>::get_Item2() + IL_0167: stloc.s V_32 + IL_0169: ldloc.s V_31 + IL_016b: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::get_Source() + IL_0170: stloc.s V_33 + IL_0172: ldloc.s V_32 + IL_0174: newobj instance void Linq101Aggregates01/'totalChars@31-2'::.ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) + IL_0179: stloc.s V_34 + IL_017b: ldloc.s V_33 + IL_017d: call class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/ISeq`1 [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToComposer(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_0182: ldloc.s V_34 + IL_0184: callvirt instance !!0 class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/ISeq`1::ForEach>(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,!!0>) + IL_0189: ldfld !1 class [FSharp.Core]Microsoft.FSharp.Collections.ComposerModule/Core/Folder`2::Value + IL_018e: dup + IL_018f: stsfld int32 ''.$Linq101Aggregates01::totalChars@28 + IL_0194: stloc.s totalChars .line 35,35 : 1,32 '' - IL_0200: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 [Utils]Utils::getProductList() - IL_0205: dup - IL_0206: stsfld class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 ''.$Linq101Aggregates01::products@35 - IL_020b: stloc.s products + IL_0196: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 [Utils]Utils::getProductList() + IL_019b: dup + IL_019c: stsfld class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 ''.$Linq101Aggregates01::products@35 + IL_01a1: stloc.s products .line 37,46 : 1,21 '' - IL_020d: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() - IL_0212: stloc.s V_41 - IL_0214: ldloc.s V_41 - IL_0216: ldloc.s V_41 - IL_0218: ldloc.s V_41 - IL_021a: ldloc.s V_41 - IL_021c: ldloc.s V_41 - IL_021e: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_products() - IL_0223: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 - IL_0228: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_022d: ldloc.s V_41 - IL_022f: newobj instance void Linq101Aggregates01/categories@39::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) - IL_0234: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_01a3: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() + IL_01a8: stloc.s V_35 + IL_01aa: ldloc.s V_35 + IL_01ac: ldloc.s V_35 + IL_01ae: ldloc.s V_35 + IL_01b0: ldloc.s V_35 + IL_01b2: ldloc.s V_35 + IL_01b4: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_products() + IL_01b9: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 + IL_01be: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_01c3: ldloc.s V_35 + IL_01c5: newobj instance void Linq101Aggregates01/categories@39::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) + IL_01ca: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>) - IL_0239: newobj instance void Linq101Aggregates01/'categories@40-1'::.ctor() - IL_023e: newobj instance void Linq101Aggregates01/'categories@40-2'::.ctor() - IL_0243: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,!!3> [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::GroupValBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_01cf: newobj instance void Linq101Aggregates01/'categories@40-1'::.ctor() + IL_01d4: newobj instance void Linq101Aggregates01/'categories@40-2'::.ctor() + IL_01d9: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,!!3> [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::GroupValBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_0248: ldloc.s V_41 - IL_024a: newobj instance void Linq101Aggregates01/'categories@40-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) - IL_024f: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2,int32>,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_01de: ldloc.s V_35 + IL_01e0: newobj instance void Linq101Aggregates01/'categories@40-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) + IL_01e5: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2,int32>,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>) - IL_0254: newobj instance void Linq101Aggregates01/'categories@45-4'::.ctor() - IL_0259: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Select,int32>,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_01ea: newobj instance void Linq101Aggregates01/'categories@45-4'::.ctor() + IL_01ef: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Select,int32>,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_025e: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,class [mscorlib]System.Collections.IEnumerable>::get_Source() - IL_0263: call !!0[] [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToArray>(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_0268: dup - IL_0269: stsfld class [mscorlib]System.Tuple`2[] ''.$Linq101Aggregates01::categories@37 - IL_026e: stloc.s categories - IL_0270: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() - IL_0275: stloc.s V_42 - IL_0277: ldloc.s V_42 - IL_0279: ldc.i4.0 - IL_027a: ldc.i4.0 - IL_027b: ldnull - IL_027c: ldc.i4.0 - IL_027d: ldc.i4.0 - IL_027e: newobj instance void Linq101Aggregates01/minNum@49::.ctor(int32, + IL_01f4: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,class [mscorlib]System.Collections.IEnumerable>::get_Source() + IL_01f9: call !!0[] [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToArray>(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_01fe: dup + IL_01ff: stsfld class [mscorlib]System.Tuple`2[] ''.$Linq101Aggregates01::categories@37 + IL_0204: stloc.s categories + IL_0206: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() + IL_020b: stloc.s V_36 + IL_020d: ldloc.s V_36 + IL_020f: ldc.i4.0 + IL_0210: ldc.i4.0 + IL_0211: ldnull + IL_0212: ldc.i4.0 + IL_0213: ldc.i4.0 + IL_0214: newobj instance void Linq101Aggregates01/minNum@49::.ctor(int32, int32, class [mscorlib]System.Collections.Generic.IEnumerator`1, int32, int32) - IL_0283: newobj instance void class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_0288: newobj instance void Linq101Aggregates01/'minNum@49-1'::.ctor() - IL_028d: callvirt instance !!2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::MinBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_0219: newobj instance void class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_021e: newobj instance void Linq101Aggregates01/'minNum@49-1'::.ctor() + IL_0223: callvirt instance !!2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::MinBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_0292: dup - IL_0293: stsfld int32 ''.$Linq101Aggregates01::minNum@49 - IL_0298: stloc.s minNum - IL_029a: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() - IL_029f: stloc.s V_43 - IL_02a1: ldloc.s V_43 - IL_02a3: ldnull - IL_02a4: ldnull - IL_02a5: ldnull - IL_02a6: ldc.i4.0 - IL_02a7: ldnull - IL_02a8: newobj instance void Linq101Aggregates01/shortestWord@52::.ctor(string, + IL_0228: dup + IL_0229: stsfld int32 ''.$Linq101Aggregates01::minNum@49 + IL_022e: stloc.s minNum + IL_0230: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() + IL_0235: stloc.s V_37 + IL_0237: ldloc.s V_37 + IL_0239: ldnull + IL_023a: ldnull + IL_023b: ldnull + IL_023c: ldc.i4.0 + IL_023d: ldnull + IL_023e: newobj instance void Linq101Aggregates01/shortestWord@52::.ctor(string, string, class [mscorlib]System.Collections.Generic.IEnumerator`1, int32, string) - IL_02ad: newobj instance void class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_02b2: newobj instance void Linq101Aggregates01/'shortestWord@52-1'::.ctor() - IL_02b7: callvirt instance !!2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::MinBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_0243: newobj instance void class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_0248: newobj instance void Linq101Aggregates01/'shortestWord@52-1'::.ctor() + IL_024d: callvirt instance !!2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::MinBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_02bc: dup - IL_02bd: stsfld int32 ''.$Linq101Aggregates01::shortestWord@52 - IL_02c2: stloc.s shortestWord + IL_0252: dup + IL_0253: stsfld int32 ''.$Linq101Aggregates01::shortestWord@52 + IL_0258: stloc.s shortestWord .line 55,61 : 1,21 '' - IL_02c4: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() - IL_02c9: stloc.s V_44 - IL_02cb: ldloc.s V_44 - IL_02cd: ldloc.s V_44 - IL_02cf: ldloc.s V_44 - IL_02d1: ldloc.s V_44 - IL_02d3: ldloc.s V_44 - IL_02d5: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_products() - IL_02da: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 - IL_02df: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_02e4: ldloc.s V_44 - IL_02e6: newobj instance void Linq101Aggregates01/categories2@57::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) - IL_02eb: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_025a: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() + IL_025f: stloc.s V_38 + IL_0261: ldloc.s V_38 + IL_0263: ldloc.s V_38 + IL_0265: ldloc.s V_38 + IL_0267: ldloc.s V_38 + IL_0269: ldloc.s V_38 + IL_026b: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_products() + IL_0270: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 + IL_0275: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_027a: ldloc.s V_38 + IL_027c: newobj instance void Linq101Aggregates01/categories2@57::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) + IL_0281: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>) - IL_02f0: newobj instance void Linq101Aggregates01/'categories2@58-1'::.ctor() - IL_02f5: newobj instance void Linq101Aggregates01/'categories2@58-2'::.ctor() - IL_02fa: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,!!3> [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::GroupValBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_0286: newobj instance void Linq101Aggregates01/'categories2@58-1'::.ctor() + IL_028b: newobj instance void Linq101Aggregates01/'categories2@58-2'::.ctor() + IL_0290: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,!!3> [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::GroupValBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_02ff: ldloc.s V_44 - IL_0301: newobj instance void Linq101Aggregates01/'categories2@58-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) - IL_0306: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2,valuetype [mscorlib]System.Decimal>,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_0295: ldloc.s V_38 + IL_0297: newobj instance void Linq101Aggregates01/'categories2@58-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) + IL_029c: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2,valuetype [mscorlib]System.Decimal>,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>) - IL_030b: newobj instance void Linq101Aggregates01/'categories2@60-4'::.ctor() - IL_0310: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Select,valuetype [mscorlib]System.Decimal>,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_02a1: newobj instance void Linq101Aggregates01/'categories2@60-4'::.ctor() + IL_02a6: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Select,valuetype [mscorlib]System.Decimal>,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_0315: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,class [mscorlib]System.Collections.IEnumerable>::get_Source() - IL_031a: call !!0[] [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToArray>(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_031f: dup - IL_0320: stsfld class [mscorlib]System.Tuple`2[] ''.$Linq101Aggregates01::categories2@55 - IL_0325: stloc.s categories2 + IL_02ab: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,class [mscorlib]System.Collections.IEnumerable>::get_Source() + IL_02b0: call !!0[] [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToArray>(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_02b5: dup + IL_02b6: stsfld class [mscorlib]System.Tuple`2[] ''.$Linq101Aggregates01::categories2@55 + IL_02bb: stloc.s categories2 .line 64,71 : 1,21 '' - IL_0327: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() - IL_032c: stloc.s V_45 - IL_032e: ldloc.s V_45 - IL_0330: ldloc.s V_45 - IL_0332: ldloc.s V_45 - IL_0334: ldloc.s V_45 - IL_0336: ldloc.s V_45 - IL_0338: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_products() - IL_033d: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 - IL_0342: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_0347: ldloc.s V_45 - IL_0349: newobj instance void Linq101Aggregates01/categories3@66::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) - IL_034e: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_02bd: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() + IL_02c2: stloc.s V_39 + IL_02c4: ldloc.s V_39 + IL_02c6: ldloc.s V_39 + IL_02c8: ldloc.s V_39 + IL_02ca: ldloc.s V_39 + IL_02cc: ldloc.s V_39 + IL_02ce: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_products() + IL_02d3: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 + IL_02d8: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_02dd: ldloc.s V_39 + IL_02df: newobj instance void Linq101Aggregates01/categories3@66::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) + IL_02e4: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>) - IL_0353: newobj instance void Linq101Aggregates01/'categories3@67-1'::.ctor() - IL_0358: newobj instance void Linq101Aggregates01/'categories3@67-2'::.ctor() - IL_035d: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,!!3> [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::GroupValBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_02e9: newobj instance void Linq101Aggregates01/'categories3@67-1'::.ctor() + IL_02ee: newobj instance void Linq101Aggregates01/'categories3@67-2'::.ctor() + IL_02f3: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,!!3> [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::GroupValBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_0362: ldloc.s V_45 - IL_0364: newobj instance void Linq101Aggregates01/'categories3@67-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) - IL_0369: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`3,valuetype [mscorlib]System.Decimal,class [mscorlib]System.Collections.Generic.IEnumerable`1>,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_02f8: ldloc.s V_39 + IL_02fa: newobj instance void Linq101Aggregates01/'categories3@67-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) + IL_02ff: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`3,valuetype [mscorlib]System.Decimal,class [mscorlib]System.Collections.Generic.IEnumerable`1>,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>) - IL_036e: newobj instance void Linq101Aggregates01/'categories3@70-4'::.ctor() - IL_0373: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Select,valuetype [mscorlib]System.Decimal,class [mscorlib]System.Collections.Generic.IEnumerable`1>,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2>>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_0304: newobj instance void Linq101Aggregates01/'categories3@70-4'::.ctor() + IL_0309: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Select,valuetype [mscorlib]System.Decimal,class [mscorlib]System.Collections.Generic.IEnumerable`1>,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2>>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_0378: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2>,class [mscorlib]System.Collections.IEnumerable>::get_Source() - IL_037d: call !!0[] [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToArray>>(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_0382: dup - IL_0383: stsfld class [mscorlib]System.Tuple`2>[] ''.$Linq101Aggregates01::categories3@64 - IL_0388: stloc.s categories3 - IL_038a: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() - IL_038f: stloc.s V_46 - IL_0391: ldloc.s V_46 - IL_0393: ldc.i4.0 - IL_0394: ldc.i4.0 - IL_0395: ldnull - IL_0396: ldc.i4.0 - IL_0397: ldc.i4.0 - IL_0398: newobj instance void Linq101Aggregates01/maxNum@74::.ctor(int32, + IL_030e: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2>,class [mscorlib]System.Collections.IEnumerable>::get_Source() + IL_0313: call !!0[] [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToArray>>(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_0318: dup + IL_0319: stsfld class [mscorlib]System.Tuple`2>[] ''.$Linq101Aggregates01::categories3@64 + IL_031e: stloc.s categories3 + IL_0320: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() + IL_0325: stloc.s V_40 + IL_0327: ldloc.s V_40 + IL_0329: ldc.i4.0 + IL_032a: ldc.i4.0 + IL_032b: ldnull + IL_032c: ldc.i4.0 + IL_032d: ldc.i4.0 + IL_032e: newobj instance void Linq101Aggregates01/maxNum@74::.ctor(int32, int32, class [mscorlib]System.Collections.Generic.IEnumerator`1, int32, int32) - IL_039d: newobj instance void class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_03a2: newobj instance void Linq101Aggregates01/'maxNum@74-1'::.ctor() - IL_03a7: callvirt instance !!2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::MaxBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_0333: newobj instance void class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_0338: newobj instance void Linq101Aggregates01/'maxNum@74-1'::.ctor() + IL_033d: callvirt instance !!2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::MaxBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_03ac: dup - IL_03ad: stsfld int32 ''.$Linq101Aggregates01::maxNum@74 - IL_03b2: stloc.s maxNum - IL_03b4: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() - IL_03b9: stloc.s V_47 - IL_03bb: ldloc.s V_47 - IL_03bd: ldnull - IL_03be: ldnull - IL_03bf: ldnull - IL_03c0: ldc.i4.0 - IL_03c1: ldnull - IL_03c2: newobj instance void Linq101Aggregates01/longestLength@77::.ctor(string, + IL_0342: dup + IL_0343: stsfld int32 ''.$Linq101Aggregates01::maxNum@74 + IL_0348: stloc.s maxNum + IL_034a: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() + IL_034f: stloc.s V_41 + IL_0351: ldloc.s V_41 + IL_0353: ldnull + IL_0354: ldnull + IL_0355: ldnull + IL_0356: ldc.i4.0 + IL_0357: ldnull + IL_0358: newobj instance void Linq101Aggregates01/longestLength@77::.ctor(string, string, class [mscorlib]System.Collections.Generic.IEnumerator`1, int32, string) - IL_03c7: newobj instance void class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_03cc: newobj instance void Linq101Aggregates01/'longestLength@77-1'::.ctor() - IL_03d1: callvirt instance !!2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::MaxBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_035d: newobj instance void class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_0362: newobj instance void Linq101Aggregates01/'longestLength@77-1'::.ctor() + IL_0367: callvirt instance !!2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::MaxBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_03d6: dup - IL_03d7: stsfld int32 ''.$Linq101Aggregates01::longestLength@77 - IL_03dc: stloc.s longestLength + IL_036c: dup + IL_036d: stsfld int32 ''.$Linq101Aggregates01::longestLength@77 + IL_0372: stloc.s longestLength .line 80,86 : 1,21 '' - IL_03de: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() - IL_03e3: stloc.s V_48 - IL_03e5: ldloc.s V_48 - IL_03e7: ldloc.s V_48 - IL_03e9: ldloc.s V_48 - IL_03eb: ldloc.s V_48 - IL_03ed: ldloc.s V_48 - IL_03ef: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_products() - IL_03f4: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 - IL_03f9: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_03fe: ldloc.s V_48 - IL_0400: newobj instance void Linq101Aggregates01/categories4@82::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) - IL_0405: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_0374: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() + IL_0379: stloc.s V_42 + IL_037b: ldloc.s V_42 + IL_037d: ldloc.s V_42 + IL_037f: ldloc.s V_42 + IL_0381: ldloc.s V_42 + IL_0383: ldloc.s V_42 + IL_0385: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_products() + IL_038a: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 + IL_038f: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_0394: ldloc.s V_42 + IL_0396: newobj instance void Linq101Aggregates01/categories4@82::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) + IL_039b: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>) - IL_040a: newobj instance void Linq101Aggregates01/'categories4@83-1'::.ctor() - IL_040f: newobj instance void Linq101Aggregates01/'categories4@83-2'::.ctor() - IL_0414: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,!!3> [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::GroupValBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_03a0: newobj instance void Linq101Aggregates01/'categories4@83-1'::.ctor() + IL_03a5: newobj instance void Linq101Aggregates01/'categories4@83-2'::.ctor() + IL_03aa: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,!!3> [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::GroupValBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_0419: ldloc.s V_48 - IL_041b: newobj instance void Linq101Aggregates01/'categories4@83-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) - IL_0420: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2,valuetype [mscorlib]System.Decimal>,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_03af: ldloc.s V_42 + IL_03b1: newobj instance void Linq101Aggregates01/'categories4@83-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) + IL_03b6: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2,valuetype [mscorlib]System.Decimal>,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>) - IL_0425: newobj instance void Linq101Aggregates01/'categories4@85-4'::.ctor() - IL_042a: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Select,valuetype [mscorlib]System.Decimal>,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_03bb: newobj instance void Linq101Aggregates01/'categories4@85-4'::.ctor() + IL_03c0: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Select,valuetype [mscorlib]System.Decimal>,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_042f: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,class [mscorlib]System.Collections.IEnumerable>::get_Source() - IL_0434: call !!0[] [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToArray>(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_0439: dup - IL_043a: stsfld class [mscorlib]System.Tuple`2[] ''.$Linq101Aggregates01::categories4@80 - IL_043f: stloc.s categories4 + IL_03c5: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,class [mscorlib]System.Collections.IEnumerable>::get_Source() + IL_03ca: call !!0[] [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToArray>(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_03cf: dup + IL_03d0: stsfld class [mscorlib]System.Tuple`2[] ''.$Linq101Aggregates01::categories4@80 + IL_03d5: stloc.s categories4 .line 89,96 : 1,21 '' - IL_0441: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() - IL_0446: stloc.s V_49 - IL_0448: ldloc.s V_49 - IL_044a: ldloc.s V_49 - IL_044c: ldloc.s V_49 - IL_044e: ldloc.s V_49 - IL_0450: ldloc.s V_49 - IL_0452: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_products() - IL_0457: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 - IL_045c: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_0461: ldloc.s V_49 - IL_0463: newobj instance void Linq101Aggregates01/categories5@91::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) - IL_0468: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_03d7: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() + IL_03dc: stloc.s V_43 + IL_03de: ldloc.s V_43 + IL_03e0: ldloc.s V_43 + IL_03e2: ldloc.s V_43 + IL_03e4: ldloc.s V_43 + IL_03e6: ldloc.s V_43 + IL_03e8: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_products() + IL_03ed: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 + IL_03f2: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_03f7: ldloc.s V_43 + IL_03f9: newobj instance void Linq101Aggregates01/categories5@91::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) + IL_03fe: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>) - IL_046d: newobj instance void Linq101Aggregates01/'categories5@92-1'::.ctor() - IL_0472: newobj instance void Linq101Aggregates01/'categories5@92-2'::.ctor() - IL_0477: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,!!3> [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::GroupValBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_0403: newobj instance void Linq101Aggregates01/'categories5@92-1'::.ctor() + IL_0408: newobj instance void Linq101Aggregates01/'categories5@92-2'::.ctor() + IL_040d: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,!!3> [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::GroupValBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_047c: ldloc.s V_49 - IL_047e: newobj instance void Linq101Aggregates01/'categories5@92-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) - IL_0483: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`3,valuetype [mscorlib]System.Decimal,class [mscorlib]System.Collections.Generic.IEnumerable`1>,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_0412: ldloc.s V_43 + IL_0414: newobj instance void Linq101Aggregates01/'categories5@92-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) + IL_0419: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`3,valuetype [mscorlib]System.Decimal,class [mscorlib]System.Collections.Generic.IEnumerable`1>,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>) - IL_0488: newobj instance void Linq101Aggregates01/'categories5@95-4'::.ctor() - IL_048d: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Select,valuetype [mscorlib]System.Decimal,class [mscorlib]System.Collections.Generic.IEnumerable`1>,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2>>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_041e: newobj instance void Linq101Aggregates01/'categories5@95-4'::.ctor() + IL_0423: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Select,valuetype [mscorlib]System.Decimal,class [mscorlib]System.Collections.Generic.IEnumerable`1>,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2>>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_0492: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2>,class [mscorlib]System.Collections.IEnumerable>::get_Source() - IL_0497: call !!0[] [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToArray>>(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_049c: dup - IL_049d: stsfld class [mscorlib]System.Tuple`2>[] ''.$Linq101Aggregates01::categories5@89 - IL_04a2: stloc.s categories5 + IL_0428: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2>,class [mscorlib]System.Collections.IEnumerable>::get_Source() + IL_042d: call !!0[] [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToArray>>(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_0432: dup + IL_0433: stsfld class [mscorlib]System.Tuple`2>[] ''.$Linq101Aggregates01::categories5@89 + IL_0438: stloc.s categories5 .line 99,99 : 1,66 '' - IL_04a4: ldc.r8 5. - IL_04ad: ldc.r8 4. - IL_04b6: ldc.r8 1. - IL_04bf: ldc.r8 3. - IL_04c8: ldc.r8 9. - IL_04d1: ldc.r8 8. - IL_04da: ldc.r8 6. - IL_04e3: ldc.r8 7. - IL_04ec: ldc.r8 2. - IL_04f5: ldc.r8 0.0 - IL_04fe: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::get_Empty() - IL_0503: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, + IL_043a: ldc.r8 5. + IL_0443: ldc.r8 4. + IL_044c: ldc.r8 1. + IL_0455: ldc.r8 3. + IL_045e: ldc.r8 9. + IL_0467: ldc.r8 8. + IL_0470: ldc.r8 6. + IL_0479: ldc.r8 7. + IL_0482: ldc.r8 2. + IL_048b: ldc.r8 0.0 + IL_0494: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::get_Empty() + IL_0499: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1) - IL_0508: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, + IL_049e: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1) - IL_050d: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, + IL_04a3: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1) - IL_0512: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, + IL_04a8: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1) - IL_0517: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, + IL_04ad: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1) - IL_051c: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, + IL_04b2: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1) - IL_0521: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, + IL_04b7: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1) - IL_0526: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, + IL_04bc: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1) - IL_052b: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, + IL_04c1: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1) - IL_0530: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, + IL_04c6: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1::Cons(!0, class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1) - IL_0535: dup - IL_0536: stsfld class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 ''.$Linq101Aggregates01::numbers2@99 - IL_053b: stloc.s numbers2 - IL_053d: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() - IL_0542: stloc.s V_50 - IL_0544: ldloc.s V_50 - IL_0546: stloc.s V_51 - IL_0548: ldc.r8 0.0 - IL_0551: ldc.r8 0.0 - IL_055a: ldnull - IL_055b: ldc.i4.0 - IL_055c: ldc.r8 0.0 - IL_0565: newobj instance void Linq101Aggregates01/averageNum@100::.ctor(float64, + IL_04cb: dup + IL_04cc: stsfld class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 ''.$Linq101Aggregates01::numbers2@99 + IL_04d1: stloc.s numbers2 + IL_04d3: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() + IL_04d8: stloc.s V_44 + IL_04da: ldloc.s V_44 + IL_04dc: stloc.s V_45 + IL_04de: ldc.r8 0.0 + IL_04e7: ldc.r8 0.0 + IL_04f0: ldnull + IL_04f1: ldc.i4.0 + IL_04f2: ldc.r8 0.0 + IL_04fb: newobj instance void Linq101Aggregates01/averageNum@100::.ctor(float64, float64, class [mscorlib]System.Collections.Generic.IEnumerator`1, int32, float64) - IL_056a: newobj instance void class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_056f: newobj instance void Linq101Aggregates01/'averageNum@100-1'::.ctor() - IL_0574: newobj instance void class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>::.ctor(!0, + IL_0500: newobj instance void class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::.ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_0505: newobj instance void Linq101Aggregates01/'averageNum@100-1'::.ctor() + IL_050a: newobj instance void class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>::.ctor(!0, !1) - IL_0579: stloc.s V_52 - IL_057b: ldloc.s V_52 - IL_057d: call instance !0 class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>::get_Item1() - IL_0582: stloc.s V_53 - IL_0584: ldloc.s V_52 - IL_0586: call instance !1 class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>::get_Item2() - IL_058b: stloc.s V_54 - IL_058d: ldloc.s V_53 - IL_058f: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::get_Source() - IL_0594: stloc.s V_55 - IL_0596: ldloc.s V_55 - IL_0598: box class [mscorlib]System.Collections.Generic.IEnumerable`1 - IL_059d: brfalse.s IL_05a1 - - IL_059f: br.s IL_05b4 + IL_050f: stloc.s V_46 + IL_0511: ldloc.s V_46 + IL_0513: call instance !0 class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>::get_Item1() + IL_0518: stloc.s V_47 + IL_051a: ldloc.s V_46 + IL_051c: call instance !1 class [mscorlib]System.Tuple`2,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>::get_Item2() + IL_0521: stloc.s V_48 + IL_0523: ldloc.s V_47 + IL_0525: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2::get_Source() + IL_052a: stloc.s V_49 + IL_052c: ldloc.s V_49 + IL_052e: box class [mscorlib]System.Collections.Generic.IEnumerable`1 + IL_0533: brfalse.s IL_0537 + + IL_0535: br.s IL_054a .line 100001,100001 : 0,0 '' - IL_05a1: ldstr "source" - IL_05a6: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) - IL_05ab: call !!0 [FSharp.Core]Microsoft.FSharp.Core.Operators::Raise(class [mscorlib]System.Exception) - IL_05b0: pop + IL_0537: ldstr "source" + IL_053c: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) + IL_0541: call !!0 [FSharp.Core]Microsoft.FSharp.Core.Operators::Raise(class [mscorlib]System.Exception) + IL_0546: pop .line 100001,100001 : 0,0 '' - IL_05b1: nop - IL_05b2: br.s IL_05b5 + IL_0547: nop + IL_0548: br.s IL_054b .line 100001,100001 : 0,0 '' .line 100001,100001 : 0,0 '' - IL_05b4: nop - IL_05b5: ldloc.s V_55 - IL_05b7: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1::GetEnumerator() - IL_05bc: stloc.s V_56 + IL_054a: nop + IL_054b: ldloc.s V_49 + IL_054d: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1::GetEnumerator() + IL_0552: stloc.s V_50 .try { - IL_05be: ldc.r8 0.0 - IL_05c7: stloc.s V_58 - IL_05c9: ldc.i4.0 - IL_05ca: stloc.s V_59 - IL_05cc: ldloc.s V_56 - IL_05ce: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() - IL_05d3: brfalse.s IL_05f1 - - IL_05d5: ldloc.s V_58 - IL_05d7: ldloc.s V_54 - IL_05d9: ldloc.s V_56 - IL_05db: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1::get_Current() - IL_05e0: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) - IL_05e5: add - IL_05e6: stloc.s V_58 + IL_0554: ldc.r8 0.0 + IL_055d: stloc.s V_52 + IL_055f: ldc.i4.0 + IL_0560: stloc.s V_53 + IL_0562: ldloc.s V_50 + IL_0564: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() + IL_0569: brfalse.s IL_0587 + + IL_056b: ldloc.s V_52 + IL_056d: ldloc.s V_48 + IL_056f: ldloc.s V_50 + IL_0571: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1::get_Current() + IL_0576: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2::Invoke(!0) + IL_057b: add + IL_057c: stloc.s V_52 .line 100,100 : 47,58 '' - IL_05e8: ldloc.s V_59 - IL_05ea: ldc.i4.1 - IL_05eb: add - IL_05ec: stloc.s V_59 + IL_057e: ldloc.s V_53 + IL_0580: ldc.i4.1 + IL_0581: add + IL_0582: stloc.s V_53 .line 100001,100001 : 0,0 '' - IL_05ee: nop - IL_05ef: br.s IL_05cc + IL_0584: nop + IL_0585: br.s IL_0562 - IL_05f1: ldloc.s V_59 - IL_05f3: brtrue.s IL_05f7 + IL_0587: ldloc.s V_53 + IL_0589: brtrue.s IL_058d - IL_05f5: br.s IL_05f9 + IL_058b: br.s IL_058f - IL_05f7: br.s IL_060c + IL_058d: br.s IL_05a2 .line 100001,100001 : 0,0 '' - IL_05f9: ldstr "source" - IL_05fe: newobj instance void [mscorlib]System.InvalidOperationException::.ctor(string) - IL_0603: call !!0 [FSharp.Core]Microsoft.FSharp.Core.Operators::Raise(class [mscorlib]System.Exception) - IL_0608: pop + IL_058f: ldstr "source" + IL_0594: newobj instance void [mscorlib]System.InvalidOperationException::.ctor(string) + IL_0599: call !!0 [FSharp.Core]Microsoft.FSharp.Core.Operators::Raise(class [mscorlib]System.Exception) + IL_059e: pop .line 100001,100001 : 0,0 '' - IL_0609: nop - IL_060a: br.s IL_060d + IL_059f: nop + IL_05a0: br.s IL_05a3 .line 100001,100001 : 0,0 '' .line 100001,100001 : 0,0 '' - IL_060c: nop - IL_060d: ldloc.s V_58 - IL_060f: stloc.s V_60 - IL_0611: ldloc.s V_59 - IL_0613: stloc.s V_61 - IL_0615: ldloc.s V_60 - IL_0617: ldloc.s V_61 - IL_0619: conv.r8 - IL_061a: div - IL_061b: stloc.s V_57 - IL_061d: leave.s IL_063d + IL_05a2: nop + IL_05a3: ldloc.s V_52 + IL_05a5: stloc.s V_54 + IL_05a7: ldloc.s V_53 + IL_05a9: stloc.s V_55 + IL_05ab: ldloc.s V_54 + IL_05ad: ldloc.s V_55 + IL_05af: conv.r8 + IL_05b0: div + IL_05b1: stloc.s V_51 + IL_05b3: leave.s IL_05d3 } // end .try finally { - IL_061f: ldloc.s V_56 - IL_0621: isinst [mscorlib]System.IDisposable - IL_0626: stloc.s V_62 - IL_0628: ldloc.s V_62 - IL_062a: brfalse.s IL_062e + IL_05b5: ldloc.s V_50 + IL_05b7: isinst [mscorlib]System.IDisposable + IL_05bc: stloc.s V_56 + IL_05be: ldloc.s V_56 + IL_05c0: brfalse.s IL_05c4 - IL_062c: br.s IL_0630 + IL_05c2: br.s IL_05c6 - IL_062e: br.s IL_063a + IL_05c4: br.s IL_05d0 .line 100001,100001 : 0,0 '' - IL_0630: ldloc.s V_62 - IL_0632: callvirt instance void [mscorlib]System.IDisposable::Dispose() - IL_0637: ldnull - IL_0638: pop - IL_0639: endfinally + IL_05c6: ldloc.s V_56 + IL_05c8: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_05cd: ldnull + IL_05ce: pop + IL_05cf: endfinally .line 100001,100001 : 0,0 '' - IL_063a: ldnull - IL_063b: pop - IL_063c: endfinally + IL_05d0: ldnull + IL_05d1: pop + IL_05d2: endfinally .line 100001,100001 : 0,0 '' } // end handler - IL_063d: ldloc.s V_57 - IL_063f: dup - IL_0640: stsfld float64 ''.$Linq101Aggregates01::averageNum@100 - IL_0645: stloc.s averageNum - IL_0647: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() - IL_064c: stloc.s V_63 - IL_064e: ldloc.s V_63 - IL_0650: stloc.s V_64 - IL_0652: ldloc.s V_63 - IL_0654: ldloc.s V_63 - IL_0656: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_words() - IL_065b: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 - IL_0660: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_0665: ldloc.s V_63 - IL_0667: newobj instance void Linq101Aggregates01/averageLength@105::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) - IL_066c: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_05d3: ldloc.s V_51 + IL_05d5: dup + IL_05d6: stsfld float64 ''.$Linq101Aggregates01::averageNum@100 + IL_05db: stloc.s averageNum + IL_05dd: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() + IL_05e2: stloc.s V_57 + IL_05e4: ldloc.s V_57 + IL_05e6: stloc.s V_58 + IL_05e8: ldloc.s V_57 + IL_05ea: ldloc.s V_57 + IL_05ec: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_words() + IL_05f1: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 + IL_05f6: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_05fb: ldloc.s V_57 + IL_05fd: newobj instance void Linq101Aggregates01/averageLength@105::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) + IL_0602: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>) - IL_0671: newobj instance void Linq101Aggregates01/'averageLength@107-1'::.ctor() - IL_0676: newobj instance void class [mscorlib]System.Tuple`2,class [mscorlib]System.Collections.IEnumerable>,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,float64>>::.ctor(!0, + IL_0607: newobj instance void Linq101Aggregates01/'averageLength@107-1'::.ctor() + IL_060c: newobj instance void class [mscorlib]System.Tuple`2,class [mscorlib]System.Collections.IEnumerable>,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,float64>>::.ctor(!0, !1) - IL_067b: stloc.s V_65 - IL_067d: ldloc.s V_65 - IL_067f: call instance !0 class [mscorlib]System.Tuple`2,class [mscorlib]System.Collections.IEnumerable>,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,float64>>::get_Item1() - IL_0684: stloc.s V_66 - IL_0686: ldloc.s V_65 - IL_0688: call instance !1 class [mscorlib]System.Tuple`2,class [mscorlib]System.Collections.IEnumerable>,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,float64>>::get_Item2() - IL_068d: stloc.s V_67 - IL_068f: ldloc.s V_66 - IL_0691: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,class [mscorlib]System.Collections.IEnumerable>::get_Source() - IL_0696: stloc.s V_68 - IL_0698: ldloc.s V_68 - IL_069a: box class [mscorlib]System.Collections.Generic.IEnumerable`1> - IL_069f: brfalse.s IL_06a3 - - IL_06a1: br.s IL_06b6 + IL_0611: stloc.s V_59 + IL_0613: ldloc.s V_59 + IL_0615: call instance !0 class [mscorlib]System.Tuple`2,class [mscorlib]System.Collections.IEnumerable>,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,float64>>::get_Item1() + IL_061a: stloc.s V_60 + IL_061c: ldloc.s V_59 + IL_061e: call instance !1 class [mscorlib]System.Tuple`2,class [mscorlib]System.Collections.IEnumerable>,class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,float64>>::get_Item2() + IL_0623: stloc.s V_61 + IL_0625: ldloc.s V_60 + IL_0627: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,class [mscorlib]System.Collections.IEnumerable>::get_Source() + IL_062c: stloc.s V_62 + IL_062e: ldloc.s V_62 + IL_0630: box class [mscorlib]System.Collections.Generic.IEnumerable`1> + IL_0635: brfalse.s IL_0639 + + IL_0637: br.s IL_064c .line 100001,100001 : 0,0 '' - IL_06a3: ldstr "source" - IL_06a8: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) - IL_06ad: call !!0 [FSharp.Core]Microsoft.FSharp.Core.Operators::Raise(class [mscorlib]System.Exception) - IL_06b2: pop + IL_0639: ldstr "source" + IL_063e: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string) + IL_0643: call !!0 [FSharp.Core]Microsoft.FSharp.Core.Operators::Raise(class [mscorlib]System.Exception) + IL_0648: pop .line 100001,100001 : 0,0 '' - IL_06b3: nop - IL_06b4: br.s IL_06b7 + IL_0649: nop + IL_064a: br.s IL_064d .line 100001,100001 : 0,0 '' .line 100001,100001 : 0,0 '' - IL_06b6: nop - IL_06b7: ldloc.s V_68 - IL_06b9: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1>::GetEnumerator() - IL_06be: stloc.s V_69 + IL_064c: nop + IL_064d: ldloc.s V_62 + IL_064f: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1 class [mscorlib]System.Collections.Generic.IEnumerable`1>::GetEnumerator() + IL_0654: stloc.s V_63 .try { - IL_06c0: ldc.r8 0.0 - IL_06c9: stloc.s V_71 - IL_06cb: ldc.i4.0 - IL_06cc: stloc.s V_72 - IL_06ce: ldloc.s V_69 - IL_06d0: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() - IL_06d5: brfalse.s IL_06f3 - - IL_06d7: ldloc.s V_71 - IL_06d9: ldloc.s V_67 - IL_06db: ldloc.s V_69 - IL_06dd: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1>::get_Current() - IL_06e2: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,float64>::Invoke(!0) - IL_06e7: add - IL_06e8: stloc.s V_71 + IL_0656: ldc.r8 0.0 + IL_065f: stloc.s V_65 + IL_0661: ldc.i4.0 + IL_0662: stloc.s V_66 + IL_0664: ldloc.s V_63 + IL_0666: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() + IL_066b: brfalse.s IL_0689 + + IL_066d: ldloc.s V_65 + IL_066f: ldloc.s V_61 + IL_0671: ldloc.s V_63 + IL_0673: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1>::get_Current() + IL_0678: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2,float64>::Invoke(!0) + IL_067d: add + IL_067e: stloc.s V_65 .line 107,107 : 9,21 '' - IL_06ea: ldloc.s V_72 - IL_06ec: ldc.i4.1 - IL_06ed: add - IL_06ee: stloc.s V_72 + IL_0680: ldloc.s V_66 + IL_0682: ldc.i4.1 + IL_0683: add + IL_0684: stloc.s V_66 .line 100001,100001 : 0,0 '' - IL_06f0: nop - IL_06f1: br.s IL_06ce + IL_0686: nop + IL_0687: br.s IL_0664 - IL_06f3: ldloc.s V_72 - IL_06f5: brtrue.s IL_06f9 + IL_0689: ldloc.s V_66 + IL_068b: brtrue.s IL_068f - IL_06f7: br.s IL_06fb + IL_068d: br.s IL_0691 - IL_06f9: br.s IL_070e + IL_068f: br.s IL_06a4 .line 100001,100001 : 0,0 '' - IL_06fb: ldstr "source" - IL_0700: newobj instance void [mscorlib]System.InvalidOperationException::.ctor(string) - IL_0705: call !!0 [FSharp.Core]Microsoft.FSharp.Core.Operators::Raise(class [mscorlib]System.Exception) - IL_070a: pop + IL_0691: ldstr "source" + IL_0696: newobj instance void [mscorlib]System.InvalidOperationException::.ctor(string) + IL_069b: call !!0 [FSharp.Core]Microsoft.FSharp.Core.Operators::Raise(class [mscorlib]System.Exception) + IL_06a0: pop .line 100001,100001 : 0,0 '' - IL_070b: nop - IL_070c: br.s IL_070f + IL_06a1: nop + IL_06a2: br.s IL_06a5 .line 100001,100001 : 0,0 '' .line 100001,100001 : 0,0 '' - IL_070e: nop - IL_070f: ldloc.s V_71 - IL_0711: stloc.s V_73 - IL_0713: ldloc.s V_72 - IL_0715: stloc.s V_74 - IL_0717: ldloc.s V_73 - IL_0719: ldloc.s V_74 - IL_071b: conv.r8 - IL_071c: div - IL_071d: stloc.s V_70 - IL_071f: leave.s IL_073f + IL_06a4: nop + IL_06a5: ldloc.s V_65 + IL_06a7: stloc.s V_67 + IL_06a9: ldloc.s V_66 + IL_06ab: stloc.s V_68 + IL_06ad: ldloc.s V_67 + IL_06af: ldloc.s V_68 + IL_06b1: conv.r8 + IL_06b2: div + IL_06b3: stloc.s V_64 + IL_06b5: leave.s IL_06d5 } // end .try finally { - IL_0721: ldloc.s V_69 - IL_0723: isinst [mscorlib]System.IDisposable - IL_0728: stloc.s V_75 - IL_072a: ldloc.s V_75 - IL_072c: brfalse.s IL_0730 + IL_06b7: ldloc.s V_63 + IL_06b9: isinst [mscorlib]System.IDisposable + IL_06be: stloc.s V_69 + IL_06c0: ldloc.s V_69 + IL_06c2: brfalse.s IL_06c6 - IL_072e: br.s IL_0732 + IL_06c4: br.s IL_06c8 - IL_0730: br.s IL_073c + IL_06c6: br.s IL_06d2 .line 100001,100001 : 0,0 '' - IL_0732: ldloc.s V_75 - IL_0734: callvirt instance void [mscorlib]System.IDisposable::Dispose() - IL_0739: ldnull - IL_073a: pop - IL_073b: endfinally + IL_06c8: ldloc.s V_69 + IL_06ca: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_06cf: ldnull + IL_06d0: pop + IL_06d1: endfinally .line 100001,100001 : 0,0 '' - IL_073c: ldnull - IL_073d: pop - IL_073e: endfinally + IL_06d2: ldnull + IL_06d3: pop + IL_06d4: endfinally .line 100001,100001 : 0,0 '' } // end handler - IL_073f: ldloc.s V_70 - IL_0741: dup - IL_0742: stsfld float64 ''.$Linq101Aggregates01::averageLength@103 - IL_0747: stloc.s averageLength + IL_06d5: ldloc.s V_64 + IL_06d7: dup + IL_06d8: stsfld float64 ''.$Linq101Aggregates01::averageLength@103 + IL_06dd: stloc.s averageLength .line 111,117 : 1,21 '' - IL_0749: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() - IL_074e: stloc.s V_76 - IL_0750: ldloc.s V_76 - IL_0752: ldloc.s V_76 - IL_0754: ldloc.s V_76 - IL_0756: ldloc.s V_76 - IL_0758: ldloc.s V_76 - IL_075a: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_products() - IL_075f: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 - IL_0764: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_0769: ldloc.s V_76 - IL_076b: newobj instance void Linq101Aggregates01/categories6@113::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) - IL_0770: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_06df: call class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::get_query() + IL_06e4: stloc.s V_70 + IL_06e6: ldloc.s V_70 + IL_06e8: ldloc.s V_70 + IL_06ea: ldloc.s V_70 + IL_06ec: ldloc.s V_70 + IL_06ee: ldloc.s V_70 + IL_06f0: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1 Linq101Aggregates01::get_products() + IL_06f5: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1 + IL_06fa: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Source(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_06ff: ldloc.s V_70 + IL_0701: newobj instance void Linq101Aggregates01/categories6@113::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) + IL_0706: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>) - IL_0775: newobj instance void Linq101Aggregates01/'categories6@114-1'::.ctor() - IL_077a: newobj instance void Linq101Aggregates01/'categories6@114-2'::.ctor() - IL_077f: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,!!3> [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::GroupValBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_070b: newobj instance void Linq101Aggregates01/'categories6@114-1'::.ctor() + IL_0710: newobj instance void Linq101Aggregates01/'categories6@114-2'::.ctor() + IL_0715: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,!!3> [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::GroupValBy(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_0784: ldloc.s V_76 - IL_0786: newobj instance void Linq101Aggregates01/'categories6@114-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) - IL_078b: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2,valuetype [mscorlib]System.Decimal>,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_071a: ldloc.s V_70 + IL_071c: newobj instance void Linq101Aggregates01/'categories6@114-3'::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder) + IL_0721: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::For,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2,valuetype [mscorlib]System.Decimal>,object>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>) - IL_0790: newobj instance void Linq101Aggregates01/'categories6@116-4'::.ctor() - IL_0795: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Select,valuetype [mscorlib]System.Decimal>,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, + IL_0726: newobj instance void Linq101Aggregates01/'categories6@116-4'::.ctor() + IL_072b: callvirt instance class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2 [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder::Select,valuetype [mscorlib]System.Decimal>,class [mscorlib]System.Collections.IEnumerable,class [mscorlib]System.Tuple`2>(class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2) - IL_079a: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,class [mscorlib]System.Collections.IEnumerable>::get_Source() - IL_079f: call !!0[] [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToArray>(class [mscorlib]System.Collections.Generic.IEnumerable`1) - IL_07a4: dup - IL_07a5: stsfld class [mscorlib]System.Tuple`2[] ''.$Linq101Aggregates01::categories6@111 - IL_07aa: stloc.s categories6 - IL_07ac: ret + IL_0730: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerable`1 class [FSharp.Core]Microsoft.FSharp.Linq.QuerySource`2,class [mscorlib]System.Collections.IEnumerable>::get_Source() + IL_0735: call !!0[] [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToArray>(class [mscorlib]System.Collections.Generic.IEnumerable`1) + IL_073a: dup + IL_073b: stsfld class [mscorlib]System.Tuple`2[] ''.$Linq101Aggregates01::categories6@111 + IL_0740: stloc.s categories6 + IL_0742: ret } // end of method $Linq101Aggregates01::main@ } // end of class ''.$Linq101Aggregates01 diff --git a/tests/fsharpqa/Source/Misc/LongSourceFile01.fs b/tests/fsharpqa/Source/Misc/LongSourceFile01.fs index 970a5f77ff6..ce49bd6d74d 100644 --- a/tests/fsharpqa/Source/Misc/LongSourceFile01.fs +++ b/tests/fsharpqa/Source/Misc/LongSourceFile01.fs @@ -163,6 +163,63 @@ Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.ICom Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]() Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString() Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void .ctor() +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean ProcessNext(T) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: TResult Value +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void .ctor(TResult) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnComplete(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnDispose() +Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand: Void StopFurtherProcessing(Int32) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Consumer`2 Create[V](IOutOfBand, System.Nullable`1[System.Int32], Consumer`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 PipeIdx +Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 get_PipeIdx() +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: ISeq`1 Compose[TResult](ISeqFactory`2) +Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: a ForEach[a](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit],a]) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Void .ctor(a, b) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Void .ctor(a, b, c) +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: a _1 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: b _2 +Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: c _3 +Microsoft.FSharp.Collections.ComposerModule+Core: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule+Core: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b] +Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c] +Microsoft.FSharp.Collections.ComposerModule+Core: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule+Core: System.Type GetType() +Microsoft.FSharp.Collections.ComposerModule: Boolean Equals(System.Object) +Microsoft.FSharp.Collections.ComposerModule: Int32 GetHashCode() +Microsoft.FSharp.Collections.ComposerModule: Microsoft.FSharp.Collections.ComposerModule+Core +Microsoft.FSharp.Collections.ComposerModule: System.String ToString() +Microsoft.FSharp.Collections.ComposerModule: System.Type GetType() Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Boolean Equals(System.Object) Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Cons Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Empty @@ -348,6 +405,7 @@ Microsoft.FSharp.Collections.SeqModule: Boolean Exists[T](Microsoft.FSharp.Core. Microsoft.FSharp.Collections.SeqModule: Boolean ForAll2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,System.Boolean]], System.Collections.Generic.IEnumerable`1[T1], System.Collections.Generic.IEnumerable`1[T2]) Microsoft.FSharp.Collections.SeqModule: Boolean ForAll[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Boolean IsEmpty[T](System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: ISeq`1 ToComposer[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 CompareWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], System.Collections.Generic.IEnumerable`1[T], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 FindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: Int32 GetHashCode() From 69753d0cea4b010c256ba7a932621b80bd9aad27 Mon Sep 17 00:00:00 2001 From: liboz Date: Sat, 15 Oct 2016 02:13:25 +0200 Subject: [PATCH 32/59] Made map2 more complex (reverted from commit ceaed6cd7cb9f842fb9b47440bff7cedeed74629) Also removed some extra null checks fixed to removing the right null check seq.tail and a fix to takewhile to use avoidtailcall --- src/fsharp/FSharp.Core/seq.fs | 96 +++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 32 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 9e8611ff507..0056bf96263 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -570,9 +570,13 @@ namespace Microsoft.FSharp.Collections inherit SeqComponentFactory<'T,'U> () override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = next.CreateMap map - and Map2Factory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = + and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map2 (map, input2, result, next) + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map2First (map, input2, result, next) + + and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = + inherit SeqComponentFactory<'Second,'U> () + override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'Second,'V> = upcast Map2Second (map, input1, result, next) and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = inherit SeqComponentFactory<'First,'U> () @@ -606,6 +610,10 @@ namespace Microsoft.FSharp.Collections inherit SeqComponentFactory<'T,'T> () override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Take (count, result, next) + and TailFactory<'T> () = + inherit SeqComponentFactory<'T,'T> () + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Tail<'T,'V> (next) + and TruncateFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Truncate (count, result, next) @@ -698,7 +706,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = Helpers.avoidTailCall (next.ProcessNext (map input)) - and Map2<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = + and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () @@ -718,6 +726,26 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () + and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:Result<'V>, next:SeqComponent<'U,'V>) = + inherit SeqComponent<'Second,'V>(next) + + let input1 = enumerable1.GetEnumerator () + let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map + + override __.ProcessNext (input:'Second) : bool = + if input1.MoveNext () then + Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) + else + result.StopFurtherProcessing () + false + + interface ISeqComponent with + override __.OnDispose () = + try + input1.Dispose () + finally + (Helpers.upcastISeqComponent next).OnDispose () + and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:Result<'V>, next:SeqComponent<'U,'V>) = inherit SeqComponent<'First,'V>(next) @@ -858,7 +886,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if predicate input then - next.ProcessNext input + Helpers.avoidTailCall (next.ProcessNext input) else result.StopFurtherProcessing () false @@ -870,6 +898,24 @@ namespace Microsoft.FSharp.Collections result.Current <- input true + and Tail<'T, 'V> (next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable first = true + + override __.ProcessNext (input:'T) : bool = + if first then + first <- false + false + else + Helpers.avoidTailCall (next.ProcessNext input) + + interface ISeqComponent with + override this.OnComplete () = + if first then + invalidArg "source" (SR.GetString(SR.notEnoughElements)) + (Helpers.upcastISeqComponent next).OnComplete () + and Truncate<'T,'V> (truncateCount:int, result:Result<'V>, next:SeqComponent<'T,'V>) = inherit SeqComponent<'T,'V>(next) @@ -956,7 +1002,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (Tail<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) @@ -967,7 +1013,7 @@ namespace Microsoft.FSharp.Collections let enumerator = enumerable.GetEnumerator () let result = Result<'U> () - let components = current.Create result (Tail result) + let components = current.Create result (Tail<'U> result) let mutable state = initialState while (not result.Halted) && (enumerator.MoveNext ()) do @@ -1069,7 +1115,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(array, current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(array, current.Create result (Tail<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(array, ComposedFactory.Combine current next)) @@ -1079,7 +1125,7 @@ namespace Microsoft.FSharp.Collections let mutable idx = 0 let result = Result<'U> () - let components = current.Create result (Tail result) + let components = current.Create result (Tail<'U> result) let mutable state = initialState while (not result.Halted) && (idx < array.Length) do @@ -1119,7 +1165,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (Tail<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) @@ -1128,7 +1174,7 @@ namespace Microsoft.FSharp.Collections let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let result = Result<'U> () - let components = current.Create result (Tail result) + let components = current.Create result (Tail<'U> result) let rec fold state lst = match result.Halted, lst with @@ -1169,7 +1215,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (Tail<'U> result), result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) @@ -1178,7 +1224,7 @@ namespace Microsoft.FSharp.Collections let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let result = Result<'U> () - let components = current.Create result (Tail result) + let components = current.Create result (Tail<'U> result) let rec fold state current = match result.Halted, generator current with @@ -1254,7 +1300,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (Tail result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (Tail<'U> result), result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) @@ -1263,7 +1309,7 @@ namespace Microsoft.FSharp.Collections let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let result = Result<'U> () - let components = current.Create result (Tail result) + let components = current.Create result (Tail<'U> result) let mutable idx = -1 let terminatingIdx = getTerminatingIdx count @@ -1524,7 +1570,9 @@ namespace Microsoft.FSharp.Collections [] let map2<'T,'U,'V> (f:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = checkNonNull "source1" source1 - source1 |> seqFactory (SeqComposer.Map2Factory (f, source2)) + match source1 with + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Compose (SeqComposer.Map2FirstFactory (f, source2)) + | _ -> source2 |> seqFactory (SeqComposer.Map2SecondFactory (f, source1)) [] let map3 f source1 source2 source3 = @@ -2255,23 +2303,7 @@ namespace Microsoft.FSharp.Collections [] let tail (source: seq<'T>) = - source |> seqFactory (Composer.Seq.TailFactory ()) - - [] - let tryLast (source : seq<_>) = - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values(true, Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun tried -> - if tried.Value._1 then - None - else - Some tried.Value._2 + source |> seqFactory (SeqComposer.TailFactory ()) [] let last (source : seq<_>) = From 19c1233b824bc8f3d44beca7f0af8bd39b739ee9 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sat, 15 Oct 2016 07:57:55 +0200 Subject: [PATCH 33/59] Seq.ofArray Seq.rev Added brackets to disambiguate Lazy Seq.permute Seq.sort(By|With|ByDescending|Descending)? Factory helper create methods for less clutter Replaced Lazy<'T> with (unit->'T) The use of lazy changed the seq's funcitonality, as it would have only been calculated once, even if the sequence was iterated again. Renamed Tail to SetResult to disambiguate Added Iter Seq.iter & Seq.average --- src/fsharp/FSharp.Core/seq.fs | 230 ++++++++++++++++++++++++---------- 1 file changed, 165 insertions(+), 65 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 0056bf96263..0fa79a25317 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -100,31 +100,6 @@ namespace Microsoft.FSharp.Collections interface System.IDisposable with member x.Dispose() = dispose() } - [] - type ArrayEnumerator<'T>(arr: 'T array) = - let mutable curr = -1 - let mutable len = arr.Length - member x.Get() = - if curr >= 0 then - if curr >= len then alreadyFinished() - else arr.[curr] - else - notStarted() - interface IEnumerator<'T> with - member x.Current = x.Get() - interface System.Collections.IEnumerator with - member x.MoveNext() = - if curr >= len then false - else - curr <- curr + 1 - (curr < len) - member x.Current = box(x.Get()) - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = () - - let ofArray arr = (new ArrayEnumerator<'T>(arr) :> IEnumerator<'T>) - [] type Singleton<'T>(v:'T) = let mutable started = false @@ -891,13 +866,6 @@ namespace Microsoft.FSharp.Collections result.StopFurtherProcessing () false - and Tail<'T> (result:Result<'T>) = - inherit SeqComponent<'T,'T>(seqComponentTail) - - override __.ProcessNext (input:'T) : bool = - result.Current <- input - true - and Tail<'T, 'V> (next:SeqComponent<'T,'V>) = inherit SeqComponent<'T,'V>(next) @@ -933,6 +901,14 @@ namespace Microsoft.FSharp.Collections result.StopFurtherProcessing () false + // SetResult<> is used at the end of the chain of SeqComponents to assign the final value + type SetResult<'T> (result:Result<'T>) = + inherit SeqComponent<'T,'T>(seqComponentTail) + + override __.ProcessNext (input:'T) : bool = + result.Current <- input + true + module Enumerable = [] type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ISeqComponent) = @@ -955,9 +931,10 @@ namespace Microsoft.FSharp.Collections | _ -> failwith "library implementation error: all states should have been handled" and [] EnumerableBase<'T> () = - abstract member Compose<'U> : (SeqComponentFactory<'T,'U>) -> IEnumerable<'U> - abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> + abstract member Compose<'U> : (SeqComponentFactory<'T,'U>) -> IEnumerable<'U> + abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> abstract member Fold<'State> : folder:('State->'T->'State) -> state:'State -> 'State + abstract member Iter : f:('T->unit) -> unit default this.Append source = Helpers.upcastEnumerable (AppendEnumerable [this; source]) @@ -1002,18 +979,28 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (Tail<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (SetResult<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) + override this.Iter (f:'U->unit) : unit = + let enumerator = enumerable.GetEnumerator () + let result = Result<'U> () + + let components = current.Create result (SetResult<'U> result) + + while (not result.Halted) && (enumerator.MoveNext ()) do + if components.ProcessNext (enumerator.Current) then + f result.Current + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let enumerator = enumerable.GetEnumerator () let result = Result<'U> () - let components = current.Create result (Tail<'U> result) + let components = current.Create result (SetResult<'U> result) let mutable state = initialState while (not result.Halted) && (enumerator.MoveNext ()) do @@ -1074,6 +1061,13 @@ namespace Microsoft.FSharp.Collections override this.Append source = Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) + override this.Iter (f:'T->unit) : unit = + let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) + let enumerator = enumerable.GetEnumerator () + + while enumerator.MoveNext () do + f enumerator.Current + override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder @@ -1086,11 +1080,23 @@ namespace Microsoft.FSharp.Collections state + let create enumerable current = + Helpers.upcastEnumerable (Enumerable(enumerable, current)) + module Array = - type Enumerator<'T,'U>(array:array<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let mutable idx = 0 + let mutable array = Unchecked.defaultof<_> + + let mutable initMoveNext = Unchecked.defaultof<_> + do + initMoveNext <- + fun () -> + result.SeqState <- SeqProcessNextStates.InProcess + array <- delayedArray () + initMoveNext <- ignore let rec moveNext () = if (not result.Halted) && idx < array.Length then @@ -1106,27 +1112,39 @@ namespace Microsoft.FSharp.Collections interface IEnumerator with member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess + initMoveNext () moveNext () - type Enumerable<'T,'U>(array:array<'T>, current:SeqComponentFactory<'T,'U>) = + type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(array, current.Create result (Tail<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result (SetResult<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.upcastEnumerable (new Enumerable<'T,'V>(array, ComposedFactory.Combine current next)) + Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) + + override this.Iter (f:'U->unit) : unit = + let mutable idx = 0 + let result = Result<'U> () + let components = current.Create result (SetResult<'U> result) + + let array = delayedArray () + while (not result.Halted) && (idx < array.Length) do + if components.ProcessNext array.[idx] then + f result.Current + idx <- idx + 1 override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let mutable idx = 0 let result = Result<'U> () - let components = current.Create result (Tail<'U> result) + let components = current.Create result (SetResult<'U> result) + let array = delayedArray () let mutable state = initialState while (not result.Halted) && (idx < array.Length) do if components.ProcessNext array.[idx] then @@ -1135,6 +1153,18 @@ namespace Microsoft.FSharp.Collections state + let createDelayed (delayedArray:unit->array<'T>) (current:SeqComponentFactory<'T,'U>) = + Helpers.upcastEnumerable (Enumerable(delayedArray, current)) + + let create (array:array<'T>) (current:SeqComponentFactory<'T,'U>) = + createDelayed (fun () -> array) current + + let createDelayedId (delayedArray:unit -> array<'T>) = + createDelayed delayedArray (IdentityFactory ()) + + let createId (array:array<'T>) = + create array (IdentityFactory ()) + module List = type Enumerator<'T,'U>(alist:list<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) @@ -1165,16 +1195,33 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (Tail<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (SetResult<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) + override this.Iter (f:'U->unit) : unit = + let result = Result<'U> () + let components = current.Create result (SetResult<'U> result) + + let rec fold lst = + match result.Halted, lst with + | true, _ + | false, [] -> () + | false, hd :: tl -> + if components.ProcessNext hd then + f result.Current + fold tl + else + fold tl + + fold alist + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let result = Result<'U> () - let components = current.Create result (Tail<'U> result) + let components = current.Create result (SetResult<'U> result) let rec fold state lst = match result.Halted, lst with @@ -1188,6 +1235,9 @@ namespace Microsoft.FSharp.Collections fold initialState alist + let create alist current = + Helpers.upcastEnumerable (Enumerable(alist, current)) + module Unfold = type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:SeqComponent<'T,'U>, signal:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) @@ -1215,16 +1265,33 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (Tail<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (SetResult<'U> result), result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + override this.Iter (f:'U->unit) : unit = + let result = Result<'U> () + let components = current.Create result (SetResult<'U> result) + + let rec fold current = + match result.Halted, generator current with + | true, _ + | false, None -> () + | false, Some (item, next) -> + if components.ProcessNext item then + f result.Current + fold next + else + fold next + + fold state + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let result = Result<'U> () - let components = current.Create result (Tail<'U> result) + let components = current.Create result (SetResult<'U> result) let rec fold state current = match result.Halted, generator current with @@ -1300,16 +1367,34 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (Tail<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (SetResult<'U> result), result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + override this.Iter (iter:'U->unit) : unit = + let result = Result<'U> () + let components = current.Create result (SetResult<'U> result) + + let mutable idx = -1 + let terminatingIdx = getTerminatingIdx count + + let mutable maybeSkipping = true + + while (not result.Halted) && (idx < terminatingIdx) do + if maybeSkipping then + maybeSkipping <- components.Skipping () + + if (not maybeSkipping) && (components.ProcessNext (f (idx+1))) then + iter result.Current + + idx <- idx + 1 + override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let result = Result<'U> () - let components = current.Create result (Tail<'U> result) + let components = current.Create result (SetResult<'U> result) let mutable idx = -1 let terminatingIdx = getTerminatingIdx count @@ -1391,6 +1476,12 @@ namespace Microsoft.FSharp.Collections override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) + override this.Iter (f:'T->unit): unit = + let enumerator = (Helpers.upcastEnumerable this).GetEnumerator () + + while enumerator.MoveNext () do + f enumerator.Current + override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder @@ -1446,7 +1537,14 @@ namespace Microsoft.FSharp.Collections [] let iter f (source : seq<'T>) = - Composer.Seq.iter f (toComposer source) + checkNonNull "source" source + checkNonNull "source" source + match source with + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Iter f + | _ -> + use e = source.GetEnumerator() + while e.MoveNext() do + f e.Current [] let tryHead (source : seq<_>) = @@ -1539,9 +1637,9 @@ namespace Microsoft.FSharp.Collections checkNonNull "source" source match source with | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Compose createSeqComponent - | :? array<'T> as a -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Array.Enumerable<_,_>(a, createSeqComponent)) - | :? list<'T> as a -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.List.Enumerable<_,_>(a, createSeqComponent)) - | _ -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Enumerable.Enumerable<_,_>(source, createSeqComponent)) + | :? array<'T> as a -> SeqComposer.Array.create a createSeqComponent + | :? list<'T> as a -> SeqComposer.List.create a createSeqComponent + | _ -> SeqComposer.Enumerable.create source createSeqComponent [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = @@ -1765,7 +1863,7 @@ namespace Microsoft.FSharp.Collections [] let ofArray (source : 'T array) = checkNonNull "source" source - Upcast.enumerable (Composer.Seq.Array.createId source) + SeqComposer.Array.createId source [] let toArray (source : seq<'T>) = @@ -2015,7 +2113,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceBy keyf array array - Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedSort) + SeqComposer.Array.createDelayedId delayedSort [] let sort source = @@ -2024,7 +2122,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlace array array - Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedSort) + SeqComposer.Array.createDelayedId delayedSort [] let sortWith f source = @@ -2033,7 +2131,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceWith f array array - Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedSort) + SeqComposer.Array.createDelayedId delayedSort [] let inline sortByDescending keyf source = @@ -2102,13 +2200,15 @@ namespace Microsoft.FSharp.Collections [] let inline average (source: seq< ^a>) : ^a = - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'a, Composer.Core.Values<'a, int>> (Composer.Core.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with - override this.ProcessNext value = - this.Value._1 <- Checked.(+) this.Value._1 value - this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + checkNonNull "source" source + let mutable acc = LanguagePrimitives.GenericZero< ^a> + let mutable count = 0 + source |> iter (fun current -> + acc <- Checked.(+) acc current + count <- count + 1) + if count = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + LanguagePrimitives.DivideByInt< ^a> acc count member this.OnComplete _ = if this.Value._2 = 0 then @@ -2339,7 +2439,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.Reverse array array - Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedReverse) + SeqComposer.Array.createDelayedId delayedReverse [] let permute f (source:seq<_>) = @@ -2348,7 +2448,7 @@ namespace Microsoft.FSharp.Collections source |> toArray |> Array.permute f - Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedPermute) + SeqComposer.Array.createDelayedId delayedPermute [] let mapFold<'T,'State,'Result> (f: 'State -> 'T -> 'Result * 'State) acc source = From a5f12d798fcb0d0f9ecde412fca3c52387afef40 Mon Sep 17 00:00:00 2001 From: liboz Date: Sat, 15 Oct 2016 11:34:13 -0400 Subject: [PATCH 34/59] making identity more efficient --- src/fsharp/FSharp.Core/seq.fs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 0fa79a25317..4e1648fae9f 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -538,7 +538,7 @@ namespace Microsoft.FSharp.Collections and IdentityFactory<'T> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = next.CreateMap id + override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Identity (next) override __.IsIdentity = true and MapFactory<'T,'U> (map:'T->'U) = @@ -673,6 +673,12 @@ namespace Microsoft.FSharp.Collections else false + and Identity<'T,'V> (next:SeqComponent<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + Helpers.avoidTailCall (next.ProcessNext input) + and Map<'T,'U,'V> (map:'T->'U, next:SeqComponent<'U,'V>) = inherit SeqComponent<'T,'V>(next) From 4b637569f4cf18cd080983a787c2b2f788a2bf19 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sun, 16 Oct 2016 01:09:42 +0200 Subject: [PATCH 35/59] Updated NoNeedToTailcall for Seq.iter changes Added OnComplete calls to Iter and Folds Experimental ForEach Currently this is only implemented on Array. This adds some public surface to the SeqComposer which may be removed. Fixed signature file, so can now use object expression Provided all ForEach implementations Removed Fold Remove Iter --- src/fsharp/FSharp.Core/seq.fs | 478 +++++++++--------- src/fsharp/FSharp.Core/seq.fsi | 27 +- ...tailcalls.NoNeedToTailcall.output.test.bsl | 2 +- 3 files changed, 268 insertions(+), 239 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 4e1648fae9f..e718d73879c 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -453,9 +453,6 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = -// type ISeqEnumerable<'T> = -// abstract member Fold<'State> : folder:('State->'T->'State) -> state:'State -> 'State - module SeqComposer = open IEnumerator @@ -463,6 +460,27 @@ namespace Microsoft.FSharp.Collections abstract OnComplete : unit -> unit abstract OnDispose : unit -> unit + type ISeqPipeline = + abstract StopFurtherProcessing : unit -> unit + + [] + type SeqConsumer<'T,'U> () = + abstract ProcessNext : input:'T -> bool + + interface ISeqComponent with + member __.OnComplete() = () + member __.OnDispose() = () + + [] + type AccumulatingConsumer<'T, 'U>(initialState:'U) = + inherit SeqConsumer<'T,'T>() + + member val Accumulator = initialState with get, set + + [] + type SeqEnumerable<'T>() = + abstract member ForEach<'a when 'a :> SeqConsumer<'T,'T>> : f:(ISeqPipeline->'a) -> 'a + module Helpers = // used for performance reasons; these are not recursive calls, so should be safe // ** it should be noted that potential changes to the f# compiler may render this function @@ -475,21 +493,8 @@ namespace Microsoft.FSharp.Collections let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) let inline upcastISeqComponent (t:#ISeqComponent) : ISeqComponent = (# "" t : ISeqComponent #) + let inline upcastSeqConsumer (t:#SeqConsumer<'a,'b>) : SeqConsumer<'a,'b> = (# "" t : SeqConsumer<'a,'b> #) - type SeqProcessNextStates = - | InProcess = 0 - | NotStarted = 1 - | Finished = 2 - - type Result<'T>() = - let mutable halted = false - - member val SeqState = SeqProcessNextStates.NotStarted with get, set - - member __.StopFurtherProcessing () = halted <- true - member __.Halted = halted - - member val Current = Unchecked.defaultof<'T> with get, set let seqComponentTail = { new ISeqComponent with @@ -497,14 +502,15 @@ namespace Microsoft.FSharp.Collections member __.OnDispose() = () } type [] SeqComponentFactory<'T,'U> () = - abstract Create<'V> : Result<'V> -> SeqComponent<'U,'V> -> SeqComponent<'T,'V> + abstract Create<'V> : ISeqPipeline -> SeqConsumer<'U,'V> -> SeqConsumer<'T,'V> abstract IsIdentity : bool default __.IsIdentity = false and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>) = inherit SeqComponentFactory<'T,'V> () - override __.Create<'W> (result:Result<'W>) (next:SeqComponent<'V,'W>) : SeqComponent<'T,'W> = first.Create result (second.Create result next) + override __.Create<'W> (result:ISeqPipeline) (next:SeqConsumer<'V,'W>) : SeqConsumer<'T,'W> = + first.Create result (second.Create result next) static member Combine (first:SeqComponentFactory<'T,'U>) (second:SeqComponentFactory<'U,'V>) : SeqComponentFactory<'T,'V> = let castToTV (factory:obj) = @@ -518,83 +524,89 @@ namespace Microsoft.FSharp.Collections and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Choose (filter, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = upcast Choose (filter, next) and DistinctFactory<'T when 'T: equality> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Distinct (next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Distinct (next) and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast DistinctBy (keyFunction, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast DistinctBy (keyFunction, next) and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Except (itemsToExclude, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Except (itemsToExclude, next) and FilterFactory<'T> (filter:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = next.CreateFilter filter + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = + match next with + | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter + | _ -> upcast Filter (filter, next) and IdentityFactory<'T> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Identity (next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Identity (next) override __.IsIdentity = true and MapFactory<'T,'U> (map:'T->'U) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = next.CreateMap map + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = + match next with + | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map + | _ -> upcast Map<_,_,_> (map, next) and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map2First (map, input2, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'First,'V> = upcast Map2First (map, input2, result, next) and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = inherit SeqComponentFactory<'Second,'U> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'Second,'V> = upcast Map2Second (map, input1, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'Second,'V> = upcast Map2Second (map, input1, result, next) and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Map3 (map, input2, input3, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'First,'V> = upcast Map3 (map, input2, input3, result, next) and MapiFactory<'T,'U> (mapi:int->'T->'U) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'T,'V> = upcast Mapi (mapi, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = upcast Mapi (mapi, next) and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'U,'V>) : SeqComponent<'First,'V> = upcast Mapi2 (map, input2, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'First,'V> = upcast Mapi2 (map, input2, result, next) and PairwiseFactory<'T> () = inherit SeqComponentFactory<'T,'T*'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T*'T,'V>) : SeqComponent<'T,'V> = upcast Pairwise next + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T*'T,'V>) : SeqConsumer<'T,'V> = upcast Pairwise next and SkipFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Skip (count, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Skip (count, next) and SkipWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast SkipWhile (predicate, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast SkipWhile (predicate, next) and TakeWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast TakeWhile (predicate, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast TakeWhile (predicate, result, next) and TakeFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Take (count, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Take (count, result, next) and TailFactory<'T> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Tail<'T,'V> (next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Tail<'T,'V> (next) and TruncateFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:Result<'V>) (next:SeqComponent<'T,'V>) : SeqComponent<'T,'V> = upcast Truncate (count, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Truncate (count, result, next) and [] SeqComponent<'T,'U> (next:ISeqComponent) = - abstract ProcessNext : input:'T -> bool + inherit SeqConsumer<'T,'U>() // Seq.init(Infinite)? lazily uses Current. The only SeqComposer component that can do that is Skip // and it can only do it at the start of a sequence @@ -612,7 +624,7 @@ namespace Microsoft.FSharp.Collections default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) - and Choose<'T,'U,'V> (choose:'T->option<'U>, next:SeqComponent<'U,'V>) = + and Choose<'T,'U,'V> (choose:'T->option<'U>, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = @@ -620,7 +632,7 @@ namespace Microsoft.FSharp.Collections | Some value -> Helpers.avoidTailCall (next.ProcessNext value) | None -> false - and Distinct<'T,'V when 'T: equality> (next:SeqComponent<'T,'V>) = + and Distinct<'T,'V when 'T: equality> (next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) @@ -631,7 +643,7 @@ namespace Microsoft.FSharp.Collections else false - and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:SeqComponent<'T,'V>) = + and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) @@ -642,7 +654,7 @@ namespace Microsoft.FSharp.Collections else false - and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:SeqComponent<'T,'V>) = + and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) @@ -653,7 +665,7 @@ namespace Microsoft.FSharp.Collections else false - and Filter<'T,'V> (filter:'T->bool, next:SeqComponent<'T,'V>) = + and Filter<'T,'V> (filter:'T->bool, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) @@ -664,7 +676,7 @@ namespace Microsoft.FSharp.Collections else false - and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:SeqComponent<'U,'V>) = + and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = @@ -673,13 +685,13 @@ namespace Microsoft.FSharp.Collections else false - and Identity<'T,'V> (next:SeqComponent<'T,'V>) = + and Identity<'T,'V> (next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = Helpers.avoidTailCall (next.ProcessNext input) - and Map<'T,'U,'V> (map:'T->'U, next:SeqComponent<'U,'V>) = + and Map<'T,'U,'V> (map:'T->'U, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'T,'V>(next) override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) @@ -687,7 +699,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = Helpers.avoidTailCall (next.ProcessNext (map input)) - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = + and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () @@ -707,7 +719,7 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:Result<'V>, next:SeqComponent<'U,'V>) = + and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'Second,'V>(next) let input1 = enumerable1.GetEnumerator () @@ -727,7 +739,7 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:Result<'V>, next:SeqComponent<'U,'V>) = + and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () @@ -751,7 +763,7 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqComponent<'U,'V>) = + and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = @@ -761,7 +773,7 @@ namespace Microsoft.FSharp.Collections else false - and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:SeqComponent<'U,'V>) = + and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'T,'V>(next) let mutable idx = 0 @@ -771,7 +783,7 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) - and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:Result<'V>, next:SeqComponent<'U,'V>) = + and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'First,'V>(next) let mutable idx = 0 @@ -793,7 +805,7 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and Pairwise<'T,'V> (next:SeqComponent<'T*'T,'V>) = + and Pairwise<'T,'V> (next:SeqConsumer<'T*'T,'V>) = inherit SeqComponent<'T,'V>(next) let mutable isFirst = true @@ -809,7 +821,7 @@ namespace Microsoft.FSharp.Collections lastValue <- input Helpers.avoidTailCall (next.ProcessNext currentPair) - and Skip<'T,'V> (skipCount:int, next:SeqComponent<'T,'V>) = + and Skip<'T,'V> (skipCount:int, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let mutable count = 0 @@ -836,7 +848,7 @@ namespace Microsoft.FSharp.Collections [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] (Helpers.upcastISeqComponent next).OnComplete () - and SkipWhile<'T,'V> (predicate:'T->bool, next:SeqComponent<'T,'V>) = + and SkipWhile<'T,'V> (predicate:'T->bool, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let mutable skip = true @@ -851,7 +863,7 @@ namespace Microsoft.FSharp.Collections else Helpers.avoidTailCall (next.ProcessNext input) - and Take<'T,'V> (takeCount:int, result:Result<'V>, next:SeqComponent<'T,'V>) = + and Take<'T,'V> (takeCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>) = inherit Truncate<'T, 'V>(takeCount, result, next) interface ISeqComponent with @@ -862,7 +874,7 @@ namespace Microsoft.FSharp.Collections [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] (Helpers.upcastISeqComponent next).OnComplete () - and TakeWhile<'T,'V> (predicate:'T->bool, result:Result<'V>, next:SeqComponent<'T,'V>) = + and TakeWhile<'T,'V> (predicate:'T->bool, result:ISeqPipeline, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = @@ -872,7 +884,7 @@ namespace Microsoft.FSharp.Collections result.StopFurtherProcessing () false - and Tail<'T, 'V> (next:SeqComponent<'T,'V>) = + and Tail<'T, 'V> (next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let mutable first = true @@ -890,7 +902,7 @@ namespace Microsoft.FSharp.Collections invalidArg "source" (SR.GetString(SR.notEnoughElements)) (Helpers.upcastISeqComponent next).OnComplete () - and Truncate<'T,'V> (truncateCount:int, result:Result<'V>, next:SeqComponent<'T,'V>) = + and Truncate<'T,'V> (truncateCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) let mutable count = 0 @@ -907,9 +919,24 @@ namespace Microsoft.FSharp.Collections result.StopFurtherProcessing () false + type SeqProcessNextStates = + | InProcess = 0 + | NotStarted = 1 + | Finished = 2 + + type Result<'T>() = + let mutable halted = false + + member val Current = Unchecked.defaultof<'T> with get, set + member val SeqState = SeqProcessNextStates.NotStarted with get, set + member __.Halted = halted + + interface ISeqPipeline with + member __.StopFurtherProcessing () = halted <- true + // SetResult<> is used at the end of the chain of SeqComponents to assign the final value type SetResult<'T> (result:Result<'T>) = - inherit SeqComponent<'T,'T>(seqComponentTail) + inherit SeqConsumer<'T,'T>() override __.ProcessNext (input:'T) : bool = result.Current <- input @@ -937,10 +964,10 @@ namespace Microsoft.FSharp.Collections | _ -> failwith "library implementation error: all states should have been handled" and [] EnumerableBase<'T> () = + inherit SeqEnumerable<'T>() + abstract member Compose<'U> : (SeqComponentFactory<'T,'U>) -> IEnumerable<'U> abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> - abstract member Fold<'State> : folder:('State->'T->'State) -> state:'State -> 'State - abstract member Iter : f:('T->unit) -> unit default this.Append source = Helpers.upcastEnumerable (AppendEnumerable [this; source]) @@ -953,7 +980,8 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = failwith "library implementation error: derived class should implement (should be abstract)" - and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + + and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = inherit EnumeratorBase<'U>(result, seqComponent) let rec moveNext () = @@ -990,30 +1018,21 @@ namespace Microsoft.FSharp.Collections override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) - override this.Iter (f:'U->unit) : unit = - let enumerator = enumerable.GetEnumerator () - let result = Result<'U> () - - let components = current.Create result (SetResult<'U> result) - - while (not result.Halted) && (enumerator.MoveNext ()) do - if components.ProcessNext (enumerator.Current) then - f result.Current - - override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - - let enumerator = enumerable.GetEnumerator () - let result = Result<'U> () - - let components = current.Create result (SetResult<'U> result) - - let mutable state = initialState - while (not result.Halted) && (enumerator.MoveNext ()) do - if components.ProcessNext (enumerator.Current) then - state <- folder'.Invoke (state, result.Current) + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + let mutable halted = false + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } + + let result = f pipeline + let consumer = current.Create pipeline result - state + use enumerator = enumerable.GetEnumerator () + while (not halted) && (enumerator.MoveNext ()) do + consumer.ProcessNext enumerator.Current |> ignore + + (Helpers.upcastISeqComponent consumer).OnComplete () + + result and AppendEnumerator<'T> (sources:list>) = let sources = sources |> List.rev @@ -1067,30 +1086,29 @@ namespace Microsoft.FSharp.Collections override this.Append source = Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) - override this.Iter (f:'T->unit) : unit = - let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) - let enumerator = enumerable.GetEnumerator () - - while enumerator.MoveNext () do - f enumerator.Current + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = + let mutable halted = false + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - + let result = f pipeline + let consumer = Helpers.upcastSeqConsumer result + let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) - let enumerator = enumerable.GetEnumerator () + use enumerator = enumerable.GetEnumerator () - let mutable state = initialState while enumerator.MoveNext () do - state <- folder'.Invoke (state, enumerator.Current) - - state + consumer.ProcessNext enumerator.Current |> ignore + + (Helpers.upcastISeqComponent consumer).OnComplete () + + result let create enumerable current = Helpers.upcastEnumerable (Enumerable(enumerable, current)) module Array = - type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let mutable idx = 0 @@ -1132,32 +1150,24 @@ namespace Microsoft.FSharp.Collections override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) - override this.Iter (f:'U->unit) : unit = + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = let mutable idx = 0 - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) - - let array = delayedArray () - while (not result.Halted) && (idx < array.Length) do - if components.ProcessNext array.[idx] then - f result.Current - idx <- idx + 1 + let mutable halted = false - override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - - let mutable idx = 0 - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } + + let result = f pipeline + let consumer = current.Create pipeline result let array = delayedArray () - let mutable state = initialState - while (not result.Halted) && (idx < array.Length) do - if components.ProcessNext array.[idx] then - state <- folder'.Invoke (state, result.Current) + while (not halted) && (idx < array.Length) do + consumer.ProcessNext array.[idx] |> ignore idx <- idx + 1 - - state + + (Helpers.upcastISeqComponent consumer).OnComplete () + + result let createDelayed (delayedArray:unit->array<'T>) (current:SeqComponentFactory<'T,'U>) = Helpers.upcastEnumerable (Enumerable(delayedArray, current)) @@ -1172,7 +1182,7 @@ namespace Microsoft.FSharp.Collections create array (IdentityFactory ()) module List = - type Enumerator<'T,'U>(alist:list<'T>, seqComponent:SeqComponent<'T,'U>, result:Result<'U>) = + type Enumerator<'T,'U>(alist:list<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let mutable list = alist @@ -1206,46 +1216,31 @@ namespace Microsoft.FSharp.Collections override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) - override this.Iter (f:'U->unit) : unit = - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) - - let rec fold lst = - match result.Halted, lst with - | true, _ - | false, [] -> () - | false, hd :: tl -> - if components.ProcessNext hd then - f result.Current - fold tl - else - fold tl - - fold alist + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + let mutable halted = false + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) + let result = f pipeline + let consumer = current.Create pipeline result - let rec fold state lst = - match result.Halted, lst with + let rec iterate lst = + match halted, lst with | true, _ - | false, [] -> state + | false, [] -> (Helpers.upcastISeqComponent consumer).OnComplete () | false, hd :: tl -> - if components.ProcessNext hd then - fold (folder'.Invoke (state, result.Current)) tl - else - fold state tl + consumer.ProcessNext hd |> ignore + iterate tl - fold initialState alist + iterate alist + + result let create alist current = Helpers.upcastEnumerable (Enumerable(alist, current)) module Unfold = - type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:SeqComponent<'T,'U>, signal:Result<'U>) = + type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:SeqConsumer<'T,'U>, signal:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) let mutable current = state @@ -1276,40 +1271,25 @@ namespace Microsoft.FSharp.Collections override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) - override this.Iter (f:'U->unit) : unit = - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + let mutable halted = false + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - let rec fold current = - match result.Halted, generator current with - | true, _ - | false, None -> () - | false, Some (item, next) -> - if components.ProcessNext item then - f result.Current - fold next - else - fold next + let result = f pipeline + let consumer = current.Create pipeline result - fold state - - override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) - - let rec fold state current = - match result.Halted, generator current with + let rec iterate current = + match halted, generator current with | true, _ - | false, None -> state + | false, None -> (Helpers.upcastISeqComponent consumer).OnComplete () | false, Some (item, next) -> - if components.ProcessNext item then - fold (folder'.Invoke (state, result.Current)) next - else - fold state next + consumer.ProcessNext item |> ignore + iterate next - fold initialState state + iterate state + + result module Init = // The original implementation of "init" delayed the calculation of Current, and so it was possible @@ -1331,9 +1311,17 @@ namespace Microsoft.FSharp.Collections else System.Int32.MaxValue - type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:SeqComponent<'T,'U>, signal:Result<'U>) = + let makeIsSkipping (consumer:SeqConsumer<'T,'U>) = + match consumer with + | :? SeqComponent<'T,'U> as c -> c.Skipping + | _ -> fun () -> false + + type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:SeqConsumer<'T,'U>, signal:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) + let isSkipping = + makeIsSkipping seqComponent + let terminatingIdx = getTerminatingIdx count @@ -1347,7 +1335,7 @@ namespace Microsoft.FSharp.Collections if maybeSkipping then // Skip can only is only checked at the start of the sequence, so once // triggered, we stay triggered. - maybeSkipping <- seqComponent.Skipping () + maybeSkipping <- isSkipping () if maybeSkipping then moveNext () @@ -1378,46 +1366,34 @@ namespace Microsoft.FSharp.Collections override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) - override this.Iter (iter:'U->unit) : unit = - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) + override this.ForEach (createResult:ISeqPipeline->#SeqConsumer<'U,'U>) = + let mutable halted = false + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } + + let result = createResult pipeline + let consumer = current.Create pipeline result let mutable idx = -1 let terminatingIdx = getTerminatingIdx count - - let mutable maybeSkipping = true - - while (not result.Halted) && (idx < terminatingIdx) do - if maybeSkipping then - maybeSkipping <- components.Skipping () - if (not maybeSkipping) && (components.ProcessNext (f (idx+1))) then - iter result.Current + let isSkipping = + makeIsSkipping consumer - idx <- idx + 1 - - override this.Fold<'State> (folder:'State->'U->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - - let result = Result<'U> () - let components = current.Create result (SetResult<'U> result) - - let mutable idx = -1 - let terminatingIdx = getTerminatingIdx count - let mutable maybeSkipping = true - let mutable state = initialState - while (not result.Halted) && (idx < terminatingIdx) do + while (not halted) && (idx < terminatingIdx) do if maybeSkipping then - maybeSkipping <- components.Skipping () + maybeSkipping <- isSkipping () - if (not maybeSkipping) && (components.ProcessNext (f (idx+1))) then - state <- folder'.Invoke (state, result.Current) + if (not maybeSkipping) then + consumer.ProcessNext (f (idx+1)) |> ignore idx <- idx + 1 - - state + + (Helpers.upcastISeqComponent consumer).OnComplete () + + result let upto lastOption f = match lastOption with @@ -1482,22 +1458,22 @@ namespace Microsoft.FSharp.Collections override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) - override this.Iter (f:'T->unit): unit = - let enumerator = (Helpers.upcastEnumerable this).GetEnumerator () - - while enumerator.MoveNext () do - f enumerator.Current + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = + let mutable halted = false + let pipeline = + { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - override this.Fold<'State> (folder:'State->'T->'State) (initialState:'State) : 'State = - let folder' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - - let enumerator = (Helpers.upcastEnumerable this).GetEnumerator () + let result = f pipeline + let consumer = Helpers.upcastSeqConsumer result - let mutable state = initialState - while enumerator.MoveNext () do - state <- folder'.Invoke (state, enumerator.Current) + use enumerator = (Helpers.upcastEnumerable this).GetEnumerator () - state + while enumerator.MoveNext () do + consumer.ProcessNext enumerator.Current |> ignore + + (Helpers.upcastISeqComponent consumer).OnComplete () + + result #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions @@ -1543,10 +1519,13 @@ namespace Microsoft.FSharp.Collections [] let iter f (source : seq<'T>) = - checkNonNull "source" source checkNonNull "source" source match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Iter f + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> + s.ForEach (fun _ -> + { new SeqComposer.SeqConsumer<'T,'T> () with + override this.ProcessNext value = + f value; true }) |> ignore | _ -> use e = source.GetEnumerator() while e.MoveNext() do @@ -1766,7 +1745,24 @@ namespace Microsoft.FSharp.Collections [] let fold<'T,'State> f (x:'State) (source:seq<'T>) = - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) + checkNonNull "source" source + match source with + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) + let total = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'State> (x) with + override this.ProcessNext value = + this.Accumulator <- f.Invoke (this.Accumulator, value) + true }) + total.Accumulator + | _ -> + use e = source.GetEnumerator() + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) + let mutable state = x + while e.MoveNext() do + state <- f.Invoke(state, e.Current) + state source |> foreach (fun _ -> @@ -2186,13 +2182,21 @@ namespace Microsoft.FSharp.Collections [] let inline sum (source:seq<'a>) : 'a = - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'a,'a> (LanguagePrimitives.GenericZero) with - override this.ProcessNext value = - this.Value <- Checked.(+) this.Value value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun sum -> sum.Value + match source with + | :? SeqComposer.SeqEnumerable<'a> as s -> + let total = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator value + true }) + total.Accumulator + | _ -> + use e = source.GetEnumerator() + let mutable acc = LanguagePrimitives.GenericZero< ^a> + while e.MoveNext() do + acc <- Checked.(+) acc e.Current + acc [] let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index f06c676e4de..e3ce82eb234 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -13,6 +13,31 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = + module SeqComposer = + type ISeqComponent = + abstract OnComplete : unit -> unit + abstract OnDispose : unit -> unit + + type ISeqPipeline = + abstract StopFurtherProcessing : unit -> unit + + [] + type SeqConsumer<'T,'U> = + new : unit -> SeqConsumer<'T,'U> + abstract ProcessNext : input:'T -> bool + interface ISeqComponent + + [] + type AccumulatingConsumer<'T,'U> = + inherit SeqConsumer<'T,'T> + new : initialState:'U -> AccumulatingConsumer<'T,'U> + member Accumulator : 'U + member Accumulator : 'U with set + + [] + type SeqEnumerable<'T> = + abstract member ForEach<'a when 'a :> SeqConsumer<'T,'T>> : f:(ISeqPipeline->'a) -> 'a + /// Returns a new sequence that contains the cartesian product of the two input sequences. /// The first sequence. /// The second sequence. @@ -1350,4 +1375,4 @@ namespace Microsoft.FSharp.Collections /// /// Thrown when any of the input sequences is null. [] - val zip3: source1:seq<'T1> -> source2:seq<'T2> -> source3:seq<'T3> -> seq<'T1 * 'T2 * 'T3> \ No newline at end of file + val zip3: source1:seq<'T1> -> source2:seq<'T2> -> source3:seq<'T3> -> seq<'T1 * 'T2 * 'T3> diff --git a/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl b/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl index 5f4e677efc6..0f49d38a8dc 100644 --- a/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl +++ b/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl @@ -41,7 +41,7 @@ value simpleLibraryCall9 at line 63 does not make a critical tailcall value simpleLibraryCall10 at line 65 does not make a critical tailcall value simpleLibraryCall11 at line 66 does not make a critical tailcall value simpleLibraryCall12 at line 67 does not make a critical tailcall -value simpleLibraryCall13 at line 68 does not make a critical tailcall +value simpleLibraryCall13 at line 68 may make a critical tailcall value simpleLibraryUse14 at line 69 does not make a critical tailcall value simpleLibraryUse15 at line 70 does not make a critical tailcall value simpleLibraryUse16 at line 71 does not make a critical tailcall From 73e810fc199b3a4410230fe6030a742a0ebe932d Mon Sep 17 00:00:00 2001 From: liboz Date: Tue, 18 Oct 2016 20:18:13 -0400 Subject: [PATCH 36/59] sumby, average, averageby, max, maxby, min, minby --- src/fsharp/FSharp.Core/seq.fs | 267 +++++++++++++++++++++++++--------- 1 file changed, 196 insertions(+), 71 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index e718d73879c..4f5e35720c2 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -2200,25 +2200,50 @@ namespace Microsoft.FSharp.Collections [] let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U = - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with - override this.ProcessNext value = - this.Value <- Checked.(+) this.Value (f value) - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun sum -> sum.Value + match source with + | :? SeqComposer.SeqEnumerable<'T> as s -> + let total = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator (f value) + true }) + total.Accumulator + | _ -> + use e = source.GetEnumerator() + let mutable acc = LanguagePrimitives.GenericZero< ^U> + while e.MoveNext() do + acc <- Checked.(+) acc (f e.Current) + acc [] let inline average (source: seq< ^a>) : ^a = - checkNonNull "source" source - let mutable acc = LanguagePrimitives.GenericZero< ^a> - let mutable count = 0 - source |> iter (fun current -> - acc <- Checked.(+) acc current - count <- count + 1) - if count = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - LanguagePrimitives.DivideByInt< ^a> acc count + match source with + | :? SeqComposer.SeqEnumerable<'a> as s -> + let mutable count = 0 + let total = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator value + count <- count + 1 + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if count = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + LanguagePrimitives.DivideByInt< ^a> total.Accumulator count + | _ -> + checkNonNull "source" source + let mutable acc = LanguagePrimitives.GenericZero< ^a> + let mutable count = 0 + source |> iter (fun current -> + acc <- Checked.(+) acc current + count <- count + 1) + if count = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + LanguagePrimitives.DivideByInt< ^a> acc count member this.OnComplete _ = if this.Value._2 = 0 then @@ -2227,13 +2252,33 @@ namespace Microsoft.FSharp.Collections [] let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'T,Composer.Core.Values<'U, int>> (Composer.Core.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with - override this.ProcessNext value = - this.Value._1 <- Checked.(+) this.Value._1 (f value) - this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + match source with + | :? SeqComposer.SeqEnumerable<'T> as s -> + let mutable count = 0 + let total = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator (f value) + count <- count + 1 + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if count = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + LanguagePrimitives.DivideByInt< ^U> total.Accumulator count + | _ -> + checkNonNull "source" source + use e = source.GetEnumerator() + let mutable acc = LanguagePrimitives.GenericZero< ^U> + let mutable count = 0 + while e.MoveNext() do + acc <- Checked.(+) acc (f e.Current) + count <- count + 1 + if count = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + LanguagePrimitives.DivideByInt< ^U> acc count member this.OnComplete _ = if this.Value._2 = 0 then @@ -2242,16 +2287,34 @@ namespace Microsoft.FSharp.Collections [] let inline min (source: seq<_>) = - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value - elif value < this.Value._2 then - this.Value._2 <- value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + match source with + | :? SeqComposer.SeqEnumerable<'T> as s -> + let mutable first = false + let min = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + first <- false + if value < this.Accumulator then + this.Accumulator <- value + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + min.Accumulator + | _ -> + checkNonNull "source" source + use e = source.GetEnumerator() + if not (e.MoveNext()) then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + let mutable acc = e.Current + while e.MoveNext() do + let curr = e.Current + if curr < acc then + acc <- curr + acc member this.OnComplete _ = if this.Value._1 then @@ -2261,20 +2324,42 @@ namespace Microsoft.FSharp.Collections [] let inline minBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - match this.Value._1, f value with - | true, valueU -> - this.Value._1 <- false - this.Value._2 <- valueU - this.Value._3 <- value - | false, valueU when valueU < this.Value._2 -> - this.Value._2 <- valueU - this.Value._3 <- value - | _ -> () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + match source with + | :? SeqComposer.SeqEnumerable<'T> as s -> + let mutable first = false + let mutable acc = Unchecked.defaultof<'U> + let min = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + first <- false + let currValue = value + let curr = f currValue + if curr < acc then + acc <- curr + this.Accumulator <- value + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + min.Accumulator + | _ -> + checkNonNull "source" source + use e = source.GetEnumerator() + if not (e.MoveNext()) then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + let first = e.Current + let mutable acc = f first + let mutable accv = first + while e.MoveNext() do + let currv = e.Current + let curr = f currv + if curr < acc then + acc <- curr + accv <- currv + accv member this.OnComplete _ = if this.Value._1 then @@ -2300,16 +2385,34 @@ namespace Microsoft.FSharp.Collections *) [] let inline max (source: seq<_>) = - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value - elif value > this.Value._2 then - this.Value._2 <- value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + match source with + | :? SeqComposer.SeqEnumerable<'T> as s -> + let mutable first = false + let max = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + first <- false + if value > this.Accumulator then + this.Accumulator <- value + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + max.Accumulator + | _ -> + checkNonNull "source" source + use e = source.GetEnumerator() + if not (e.MoveNext()) then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + let mutable acc = e.Current + while e.MoveNext() do + let curr = e.Current + if curr > acc then + acc <- curr + acc member this.OnComplete _ = if this.Value._1 then @@ -2319,20 +2422,42 @@ namespace Microsoft.FSharp.Collections [] let inline maxBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - match this.Value._1, f value with - | true, valueU -> - this.Value._1 <- false - this.Value._2 <- valueU - this.Value._3 <- value - | false, valueU when valueU > this.Value._2 -> - this.Value._2 <- valueU - this.Value._3 <- value - | _ -> () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + match source with + | :? SeqComposer.SeqEnumerable<'T> as s -> + let mutable first = false + let mutable acc = Unchecked.defaultof<'U> + let min = + s.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + first <- false + let currValue = value + let curr = f currValue + if curr > acc then + acc <- curr + this.Accumulator <- value + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + min.Accumulator + | _ -> + checkNonNull "source" source + use e = source.GetEnumerator() + if not (e.MoveNext()) then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + let first = e.Current + let mutable acc = f first + let mutable accv = first + while e.MoveNext() do + let currv = e.Current + let curr = f currv + if curr > acc then + acc <- curr + accv <- currv + accv member this.OnComplete _ = if this.Value._1 then From bc9dacf22e80a43863a7113b98bedbb59aa7aad7 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Wed, 19 Oct 2016 09:20:55 +0200 Subject: [PATCH 37/59] Removed overzelous upcastSeqConsumer PE verify says no. Appease the NoNeedToTailcall file --- src/fsharp/FSharp.Core/seq.fs | 6 ++---- .../analyses/tailcalls.NoNeedToTailcall.output.test.bsl | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 4f5e35720c2..8aad815b50e 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -493,8 +493,6 @@ namespace Microsoft.FSharp.Collections let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) let inline upcastISeqComponent (t:#ISeqComponent) : ISeqComponent = (# "" t : ISeqComponent #) - let inline upcastSeqConsumer (t:#SeqConsumer<'a,'b>) : SeqConsumer<'a,'b> = (# "" t : SeqConsumer<'a,'b> #) - let seqComponentTail = { new ISeqComponent with @@ -1092,7 +1090,7 @@ namespace Microsoft.FSharp.Collections { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } let result = f pipeline - let consumer = Helpers.upcastSeqConsumer result + let consumer : SeqConsumer<'T,'T> = upcast result let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) use enumerator = enumerable.GetEnumerator () @@ -1464,7 +1462,7 @@ namespace Microsoft.FSharp.Collections { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } let result = f pipeline - let consumer = Helpers.upcastSeqConsumer result + let consumer : SeqConsumer<'T,'T> = upcast result use enumerator = (Helpers.upcastEnumerable this).GetEnumerator () diff --git a/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl b/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl index 0f49d38a8dc..5f4e677efc6 100644 --- a/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl +++ b/tests/fsharp/optimize/analyses/tailcalls.NoNeedToTailcall.output.test.bsl @@ -41,7 +41,7 @@ value simpleLibraryCall9 at line 63 does not make a critical tailcall value simpleLibraryCall10 at line 65 does not make a critical tailcall value simpleLibraryCall11 at line 66 does not make a critical tailcall value simpleLibraryCall12 at line 67 does not make a critical tailcall -value simpleLibraryCall13 at line 68 may make a critical tailcall +value simpleLibraryCall13 at line 68 does not make a critical tailcall value simpleLibraryUse14 at line 69 does not make a critical tailcall value simpleLibraryUse15 at line 70 does not make a critical tailcall value simpleLibraryUse16 at line 71 does not make a critical tailcall From 5bb660da5063a758a02665509c5ebe6546c58301 Mon Sep 17 00:00:00 2001 From: liboz Date: Thu, 20 Oct 2016 00:27:37 +0200 Subject: [PATCH 38/59] toComposer and implementing sum singleton identityfactory using tocomposer implementing previously implementing seq functions using toComposer. Also fixes a bug with the boolean checking first fix bug with bool --- src/fsharp/FSharp.Core/seq.fs | 359 ++++++++++++--------------------- src/fsharp/FSharp.Core/seq.fsi | 10 + 2 files changed, 143 insertions(+), 226 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 8aad815b50e..cf895b42eb0 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -548,6 +548,8 @@ namespace Microsoft.FSharp.Collections override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Identity (next) override __.IsIdentity = true + static member IdentityFactory = IdentityFactory<'T>() + and MapFactory<'T,'U> (map:'T->'U) = inherit SeqComponentFactory<'T,'U> () override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = @@ -1174,10 +1176,10 @@ namespace Microsoft.FSharp.Collections createDelayed (fun () -> array) current let createDelayedId (delayedArray:unit -> array<'T>) = - createDelayed delayedArray (IdentityFactory ()) + createDelayed delayedArray IdentityFactory.IdentityFactory let createId (array:array<'T>) = - create array (IdentityFactory ()) + create array IdentityFactory.IdentityFactory module List = type Enumerator<'T,'U>(alist:list<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = @@ -1500,7 +1502,7 @@ namespace Microsoft.FSharp.Collections [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> = - SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Unfold.Enumerable<'T,'T,'State>(generator, state, SeqComposer.IdentityFactory ())) + SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Unfold.Enumerable<'T,'T,'State>(generator, state, SeqComposer.IdentityFactory.IdentityFactory)) [] let empty<'T> = (EmptyEnumerable :> seq<'T>) @@ -2178,105 +2180,73 @@ namespace Microsoft.FSharp.Collections then mkDelayedSeq (fun () -> countByValueType keyf source) else mkDelayedSeq (fun () -> countByRefType keyf source) + [] + let toComposer (source:seq<'T>): SeqComposer.SeqEnumerable<'T> = + checkNonNull "source" source + match source with + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(s, SeqComposer.IdentityFactory.IdentityFactory) + | :? array<'T> as a -> upcast SeqComposer.Array.Enumerable((fun () -> a), SeqComposer.IdentityFactory.IdentityFactory) + | :? list<'T> as a -> upcast SeqComposer.List.Enumerable(a, SeqComposer.IdentityFactory.IdentityFactory) + | _ -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(source, SeqComposer.IdentityFactory.IdentityFactory) + [] let inline sum (source:seq<'a>) : 'a = - match source with - | :? SeqComposer.SeqEnumerable<'a> as s -> - let total = - s.ForEach (fun _ -> + let composedSource = toComposer source + let total = + composedSource.ForEach (fun _ -> { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with override this.ProcessNext value = this.Accumulator <- Checked.(+) this.Accumulator value true }) - total.Accumulator - | _ -> - use e = source.GetEnumerator() - let mutable acc = LanguagePrimitives.GenericZero< ^a> - while e.MoveNext() do - acc <- Checked.(+) acc e.Current - acc + total.Accumulator [] let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U = - match source with - | :? SeqComposer.SeqEnumerable<'T> as s -> - let total = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with - override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator (f value) - true }) - total.Accumulator - | _ -> - use e = source.GetEnumerator() - let mutable acc = LanguagePrimitives.GenericZero< ^U> - while e.MoveNext() do - acc <- Checked.(+) acc (f e.Current) - acc + let composedSource = toComposer source + let total = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator (f value) + true }) + total.Accumulator [] let inline average (source: seq< ^a>) : ^a = - match source with - | :? SeqComposer.SeqEnumerable<'a> as s -> - let mutable count = 0 - let total = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with - override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator value - count <- count + 1 - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if count = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - LanguagePrimitives.DivideByInt< ^a> total.Accumulator count - | _ -> - checkNonNull "source" source - let mutable acc = LanguagePrimitives.GenericZero< ^a> - let mutable count = 0 - source |> iter (fun current -> - acc <- Checked.(+) acc current - count <- count + 1) - if count = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - LanguagePrimitives.DivideByInt< ^a> acc count + let composedSource = toComposer source - member this.OnComplete _ = - if this.Value._2 = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) - |> fun total -> LanguagePrimitives.DivideByInt< ^a> total.Value._1 total.Value._2 + let mutable count = 0 + let total = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator value + count <- count + 1 + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if count = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + LanguagePrimitives.DivideByInt< ^a> total.Accumulator count [] let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = - match source with - | :? SeqComposer.SeqEnumerable<'T> as s -> - let mutable count = 0 - let total = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with - override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator (f value) - count <- count + 1 - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if count = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - LanguagePrimitives.DivideByInt< ^U> total.Accumulator count - | _ -> - checkNonNull "source" source - use e = source.GetEnumerator() - let mutable acc = LanguagePrimitives.GenericZero< ^U> - let mutable count = 0 - while e.MoveNext() do - acc <- Checked.(+) acc (f e.Current) - count <- count + 1 - if count = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - LanguagePrimitives.DivideByInt< ^U> acc count + let composedSource = toComposer source + let mutable count = 0 + let total = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + override this.ProcessNext value = + this.Accumulator <- Checked.(+) this.Accumulator (f value) + count <- count + 1 + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if count = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + LanguagePrimitives.DivideByInt< ^U> total.Accumulator count member this.OnComplete _ = if this.Value._2 = 0 then @@ -2285,85 +2255,53 @@ namespace Microsoft.FSharp.Collections [] let inline min (source: seq<_>) = - match source with - | :? SeqComposer.SeqEnumerable<'T> as s -> - let mutable first = false - let min = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = - first <- false - if value < this.Accumulator then - this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - min.Accumulator - | _ -> - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - let mutable acc = e.Current - while e.MoveNext() do - let curr = e.Current - if curr < acc then - acc <- curr - acc + let composedSource = toComposer source - member this.OnComplete _ = - if this.Value._1 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun min -> min.Value._2 + let mutable first = true + let min = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + if first then + first <- false + this.Accumulator <- value + elif value < this.Accumulator then + this.Accumulator <- value + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + min.Accumulator [] let inline minBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - match source with - | :? SeqComposer.SeqEnumerable<'T> as s -> - let mutable first = false - let mutable acc = Unchecked.defaultof<'U> - let min = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = + let composedSource = toComposer source + + let mutable first = true + let mutable acc = Unchecked.defaultof<'U> + let min = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + let currValue = value + let curr = f currValue + if first then first <- false - let currValue = value - let curr = f currValue + acc <- curr + this.Accumulator <- value + else if curr < acc then acc <- curr this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - min.Accumulator - | _ -> - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - let first = e.Current - let mutable acc = f first - let mutable accv = first - while e.MoveNext() do - let currv = e.Current - let curr = f currv - if curr < acc then - acc <- curr - accv <- currv - accv - - member this.OnComplete _ = - if this.Value._1 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun min -> min.Value._3 + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + min.Accumulator (* [] let inline minValBy (f : 'T -> 'U) (source: seq<'T>) : 'U = @@ -2383,85 +2321,54 @@ namespace Microsoft.FSharp.Collections *) [] let inline max (source: seq<_>) = - match source with - | :? SeqComposer.SeqEnumerable<'T> as s -> - let mutable first = false - let max = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = + let composedSource = toComposer source + + let mutable first = true + let max = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + if first then first <- false + this.Accumulator <- value + else if value > this.Accumulator then this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - max.Accumulator - | _ -> - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - let mutable acc = e.Current - while e.MoveNext() do - let curr = e.Current - if curr > acc then - acc <- curr - acc - - member this.OnComplete _ = - if this.Value._1 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun max -> max.Value._2 + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + max.Accumulator [] let inline maxBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - match source with - | :? SeqComposer.SeqEnumerable<'T> as s -> - let mutable first = false - let mutable acc = Unchecked.defaultof<'U> - let min = - s.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = + let composedSource = toComposer source + + let mutable first = true + let mutable acc = Unchecked.defaultof<'U> + let min = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + let currValue = value + let curr = f currValue + if first then first <- false - let currValue = value - let curr = f currValue + acc <- curr + this.Accumulator <- value + else if curr > acc then acc <- curr this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - min.Accumulator - | _ -> - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - let first = e.Current - let mutable acc = f first - let mutable accv = first - while e.MoveNext() do - let currv = e.Current - let curr = f currv - if curr > acc then - acc <- curr - accv <- currv - accv - - member this.OnComplete _ = - if this.Value._1 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun min -> min.Value._3 + true + interface SeqComposer.ISeqComponent with + member __.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + min.Accumulator (* [] diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index e3ce82eb234..87df902c3b8 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -1146,6 +1146,16 @@ namespace Microsoft.FSharp.Collections [] val inline sortByDescending : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> when 'Key : comparison + /// Builds an SeqEnumerable from the given collection. + /// + /// The input sequence. + /// + /// The result SeqEnumerable. + /// + /// Thrown when the input sequence is null. + [] + val toComposer : source:seq<'T> -> SeqComposer.SeqEnumerable<'T> + /// Returns the sum of the elements in the sequence. /// /// The elements are summed using the + operator and Zero property associated with the generated type. From 26548202ea79c9dc5c3f19e0e7f60093b22dab13 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 20 Oct 2016 07:55:58 +0200 Subject: [PATCH 39/59] Remove duplicated ISeqPipeline Just a straight cast when EnumerableBase Simplified Identity Avoid creating extra ref objects Using average as an example of using a tuple-like, but mutable, value type to tie the data closer together and avoid allocation. Ensuring that OnDispose is called from ForEach --- src/fsharp/FSharp.Core/seq.fs | 282 ++++++++++++++++----------------- src/fsharp/FSharp.Core/seq.fsi | 13 +- 2 files changed, 152 insertions(+), 143 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index cf895b42eb0..7581f7d3669 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -471,11 +471,26 @@ namespace Microsoft.FSharp.Collections member __.OnComplete() = () member __.OnDispose() = () + [] + type MutableData<'a,'b> = + val mutable _1 : 'a + val mutable _2 : 'b + + new (a:'a, b: 'b) = { + _1 = a + _2 = b + } + [] - type AccumulatingConsumer<'T, 'U>(initialState:'U) = - inherit SeqConsumer<'T,'T>() + type AccumulatingConsumer<'T, 'U> = + inherit SeqConsumer<'T,'T> + + val mutable Accumulator : 'U - member val Accumulator = initialState with get, set + new (initialState) = { + inherit SeqConsumer<'T,'T>() + Accumulator = initialState + } [] type SeqEnumerable<'T>() = @@ -501,9 +516,6 @@ namespace Microsoft.FSharp.Collections type [] SeqComponentFactory<'T,'U> () = abstract Create<'V> : ISeqPipeline -> SeqConsumer<'U,'V> -> SeqConsumer<'T,'V> - abstract IsIdentity : bool - - default __.IsIdentity = false and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>) = inherit SeqComponentFactory<'T,'V> () @@ -511,14 +523,7 @@ namespace Microsoft.FSharp.Collections first.Create result (second.Create result next) static member Combine (first:SeqComponentFactory<'T,'U>) (second:SeqComponentFactory<'U,'V>) : SeqComponentFactory<'T,'V> = - let castToTV (factory:obj) = - match factory with - | :? SeqComponentFactory<'T,'V> as result -> result - | _ -> failwith "library implementation error: they types must match when paired with identity" - - if first.IsIdentity then castToTV second - elif second.IsIdentity then castToTV first - else upcast ComposedFactory(first, second) + upcast ComposedFactory(first, second) and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () @@ -545,10 +550,9 @@ namespace Microsoft.FSharp.Collections and IdentityFactory<'T> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Identity (next) - override __.IsIdentity = true - - static member IdentityFactory = IdentityFactory<'T>() + static let singleton = IdentityFactory<'T>() + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = next + static member IdentityFactory = singleton and MapFactory<'T,'U> (map:'T->'U) = inherit SeqComponentFactory<'T,'U> () @@ -685,12 +689,6 @@ namespace Microsoft.FSharp.Collections else false - and Identity<'T,'V> (next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - Helpers.avoidTailCall (next.ProcessNext input) - and Map<'T,'U,'V> (map:'T->'U, next:SeqConsumer<'U,'V>) = inherit SeqComponent<'T,'V>(next) @@ -942,6 +940,11 @@ namespace Microsoft.FSharp.Collections result.Current <- input true + type Pipeline() = + let mutable halted = false + interface ISeqPipeline with member x.StopFurtherProcessing() = halted <- true + member __.Halted = halted + module Enumerable = [] type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ISeqComponent) = @@ -1010,6 +1013,10 @@ namespace Microsoft.FSharp.Collections and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqComponentFactory<'T,'U>) = inherit EnumerableBase<'U>() + static let iterate (enumerator:IEnumerator<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + while (not pipeline.Halted) && (enumerator.MoveNext ()) do + consumer.ProcessNext enumerator.Current |> ignore + interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1019,20 +1026,16 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let mutable halted = false - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline() let result = f pipeline let consumer = current.Create pipeline result - use enumerator = enumerable.GetEnumerator () - while (not halted) && (enumerator.MoveNext ()) do - consumer.ProcessNext enumerator.Current |> ignore - - (Helpers.upcastISeqComponent consumer).OnComplete () - - result + try + iterate enumerator pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () and AppendEnumerator<'T> (sources:list>) = let sources = sources |> List.rev @@ -1076,6 +1079,10 @@ namespace Microsoft.FSharp.Collections and AppendEnumerable<'T> (sources:list>) = inherit EnumerableBase<'T>() + static let iterate (enumerator:IEnumerator<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + while (not pipeline.Halted) && (enumerator.MoveNext ()) do + consumer.ProcessNext enumerator.Current |> ignore + interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = Helpers.upcastEnumerator (new AppendEnumerator<_> (sources)) @@ -1087,22 +1094,17 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = - let mutable halted = false - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline() let result = f pipeline let consumer : SeqConsumer<'T,'T> = upcast result - let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) use enumerator = enumerable.GetEnumerator () - - while enumerator.MoveNext () do - consumer.ProcessNext enumerator.Current |> ignore - - (Helpers.upcastISeqComponent consumer).OnComplete () - - result + try + iterate enumerator pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () let create enumerable current = Helpers.upcastEnumerable (Enumerable(enumerable, current)) @@ -1142,6 +1144,12 @@ namespace Microsoft.FSharp.Collections type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() + static let iterate (array:array<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let mutable idx = 0 + while (not pipeline.Halted) && (idx < array.Length) do + consumer.ProcessNext array.[idx] |> ignore + idx <- idx + 1 + interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1151,23 +1159,15 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let mutable idx = 0 - let mutable halted = false - - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline () let result = f pipeline let consumer = current.Create pipeline result - - let array = delayedArray () - while (not halted) && (idx < array.Length) do - consumer.ProcessNext array.[idx] |> ignore - idx <- idx + 1 - - (Helpers.upcastISeqComponent consumer).OnComplete () - - result + try + iterate (delayedArray ()) pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () let createDelayed (delayedArray:unit->array<'T>) (current:SeqComponentFactory<'T,'U>) = Helpers.upcastEnumerable (Enumerable(delayedArray, current)) @@ -1205,6 +1205,16 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext list + let iterate (alist:list<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let rec iterate lst = + match pipeline.Halted, lst with + | true, _ + | false, [] -> () + | false, hd :: tl -> + consumer.ProcessNext hd |> ignore + iterate tl + iterate alist + type Enumerable<'T,'U>(alist:list<'T>, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() @@ -1217,24 +1227,15 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let mutable halted = false - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline () let result = f pipeline let consumer = current.Create pipeline result - - let rec iterate lst = - match halted, lst with - | true, _ - | false, [] -> (Helpers.upcastISeqComponent consumer).OnComplete () - | false, hd :: tl -> - consumer.ProcessNext hd |> ignore - iterate tl - - iterate alist - - result + try + iterate alist pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () let create alist current = Helpers.upcastEnumerable (Enumerable(alist, current)) @@ -1263,6 +1264,17 @@ namespace Microsoft.FSharp.Collections type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() + static let iterate (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let rec iterate current = + match pipeline.Halted, generator current with + | true, _ + | false, None -> () + | false, Some (item, next) -> + consumer.ProcessNext item |> ignore + iterate next + + iterate state + interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1272,24 +1284,15 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let mutable halted = false - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline () let result = f pipeline let consumer = current.Create pipeline result - - let rec iterate current = - match halted, generator current with - | true, _ - | false, None -> (Helpers.upcastISeqComponent consumer).OnComplete () - | false, Some (item, next) -> - consumer.ProcessNext item |> ignore - iterate next - - iterate state - - result + try + iterate generator state pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () module Init = // The original implementation of "init" delayed the calculation of Current, and so it was possible @@ -1358,6 +1361,18 @@ namespace Microsoft.FSharp.Collections type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() + static let iterate f (terminatingIdx:int) (isSkipping) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let mutable idx = -1 + let mutable maybeSkipping = true + while (not pipeline.Halted) && (idx < terminatingIdx) do + if maybeSkipping then + maybeSkipping <- isSkipping () + + if (not maybeSkipping) then + consumer.ProcessNext (f (idx+1)) |> ignore + + idx <- idx + 1 + interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1367,33 +1382,17 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) override this.ForEach (createResult:ISeqPipeline->#SeqConsumer<'U,'U>) = - let mutable halted = false - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline () let result = createResult pipeline let consumer = current.Create pipeline result - - let mutable idx = -1 let terminatingIdx = getTerminatingIdx count - - let isSkipping = - makeIsSkipping consumer - - let mutable maybeSkipping = true - - while (not halted) && (idx < terminatingIdx) do - if maybeSkipping then - maybeSkipping <- isSkipping () - - if (not maybeSkipping) then - consumer.ProcessNext (f (idx+1)) |> ignore - - idx <- idx + 1 - - (Helpers.upcastISeqComponent consumer).OnComplete () - - result + let isSkipping = makeIsSkipping consumer + try + iterate f terminatingIdx isSkipping pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () let upto lastOption f = match lastOption with @@ -1448,6 +1447,10 @@ namespace Microsoft.FSharp.Collections type EnumerableDecider<'T>(count:Nullable, f:int->'T) = inherit Enumerable.EnumerableBase<'T>() + static let iterate (enumerator:IEnumerator<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'T>) = + while (not pipeline.Halted) && (enumerator.MoveNext ()) do + consumer.ProcessNext enumerator.Current |> ignore + interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = // we defer back to the original implementation as, as it's quite idiomatic in it's decision @@ -1459,21 +1462,16 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = - let mutable halted = false - let pipeline = - { new ISeqPipeline with member x.StopFurtherProcessing() = halted <- true } - + let pipeline = Pipeline () let result = f pipeline let consumer : SeqConsumer<'T,'T> = upcast result - use enumerator = (Helpers.upcastEnumerable this).GetEnumerator () - - while enumerator.MoveNext () do - consumer.ProcessNext enumerator.Current |> ignore - - (Helpers.upcastISeqComponent consumer).OnComplete () - - result + try + iterate enumerator pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions @@ -2184,11 +2182,13 @@ namespace Microsoft.FSharp.Collections let toComposer (source:seq<'T>): SeqComposer.SeqEnumerable<'T> = checkNonNull "source" source match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(s, SeqComposer.IdentityFactory.IdentityFactory) + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> upcast s | :? array<'T> as a -> upcast SeqComposer.Array.Enumerable((fun () -> a), SeqComposer.IdentityFactory.IdentityFactory) | :? list<'T> as a -> upcast SeqComposer.List.Enumerable(a, SeqComposer.IdentityFactory.IdentityFactory) | _ -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(source, SeqComposer.IdentityFactory.IdentityFactory) + let inline foreach f (source:SeqComposer.SeqEnumerable<_>) = source.ForEach f + [] let inline sum (source:seq<'a>) : 'a = let composedSource = toComposer source @@ -2213,22 +2213,22 @@ namespace Microsoft.FSharp.Collections [] let inline average (source: seq< ^a>) : ^a = - let composedSource = toComposer source - - let mutable count = 0 let total = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with + source + |> toComposer + |> foreach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'a, SeqComposer.MutableData<'a, int>> (SeqComposer.MutableData(LanguagePrimitives.GenericZero, 0)) with override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator value - count <- count + 1 + this.Accumulator._1 <- Checked.(+) this.Accumulator._1 value + this.Accumulator._2 <- this.Accumulator._2 + 1 true + interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if count = 0 then + member this.OnComplete() = + if (this:?>SeqComposer.AccumulatingConsumer<'a, SeqComposer.MutableData<'a, int>>).Accumulator._2 = 0 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) - LanguagePrimitives.DivideByInt< ^a> total.Accumulator count + LanguagePrimitives.DivideByInt< ^a> total.Accumulator._1 total.Accumulator._2 [] let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index 87df902c3b8..443286c3fa0 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -27,12 +27,21 @@ namespace Microsoft.FSharp.Collections abstract ProcessNext : input:'T -> bool interface ISeqComponent + [] + type MutableData<'a,'b> = + struct + new : a:'a * b:'b -> MutableData<'a,'b> + val mutable _1: 'a + val mutable _2: 'b + end + [] type AccumulatingConsumer<'T,'U> = + class inherit SeqConsumer<'T,'T> new : initialState:'U -> AccumulatingConsumer<'T,'U> - member Accumulator : 'U - member Accumulator : 'U with set + val mutable Accumulator: 'U + end [] type SeqEnumerable<'T> = From ef8364ba33f137fe6ba99d20868e1c589353bd0c Mon Sep 17 00:00:00 2001 From: liboz Date: Thu, 20 Oct 2016 13:24:44 +0200 Subject: [PATCH 40/59] Seq.iteri, exists, contains, forall, trypick, pick, tryfind, find, reduce, last, trylast cleanup for Seq.iter, fold Also moves the functions in the seq.fsi file to be alphabetical passing false on process next when ending. fix bug where unfold did not respect the Halted state on Result --- src/fsharp/FSharp.Core/seq.fs | 210 +++++++++++++++++++++++---------- src/fsharp/FSharp.Core/seq.fsi | 12 +- 2 files changed, 146 insertions(+), 76 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 7581f7d3669..91f55e81e26 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -1247,9 +1247,10 @@ namespace Microsoft.FSharp.Collections let mutable current = state let rec moveNext () = - match generator current with - | None -> false - | Some (item, nextState) -> + match signal.Halted, generator current with + | true, _ + | false, None -> false + | false, Some (item, nextState) -> current <- nextState if seqComponent.ProcessNext item then true @@ -1481,8 +1482,15 @@ namespace Microsoft.FSharp.Collections let inline indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) [] - let toComposer (source:seq<'T>): Composer.Core.ISeq<'T> = - Composer.Seq.toComposer source + let toComposer (source:seq<'T>): SeqComposer.SeqEnumerable<'T> = + checkNonNull "source" source + match source with + | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> upcast s + | :? array<'T> as a -> upcast SeqComposer.Array.Enumerable((fun () -> a), SeqComposer.IdentityFactory.IdentityFactory) + | :? list<'T> as a -> upcast SeqComposer.List.Enumerable(a, SeqComposer.IdentityFactory.IdentityFactory) + | _ -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(source, SeqComposer.IdentityFactory.IdentityFactory) + + let inline foreach f (source:SeqComposer.SeqEnumerable<_>) = source.ForEach f let inline foreach f (source:seq<_>) = Composer.Seq.foreach f (toComposer source) @@ -1517,17 +1525,13 @@ namespace Microsoft.FSharp.Collections [] let iter f (source : seq<'T>) = - checkNonNull "source" source - match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> - s.ForEach (fun _ -> + source + |> toComposer + |> foreach (fun _ -> { new SeqComposer.SeqConsumer<'T,'T> () with override this.ProcessNext value = - f value; true }) |> ignore - | _ -> - use e = source.GetEnumerator() - while e.MoveNext() do - f e.Current + f value; true }) + |> ignore [] let tryHead (source : seq<_>) = @@ -1557,20 +1561,70 @@ namespace Microsoft.FSharp.Collections let nth i (source : seq<'T>) = item i source [] - let iteri f (source:seq<'T>) = - Composer.Seq.iteri f (toComposer source) + let iteri f (source : seq<'T>) = + let composedSource = toComposer source + + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) + let mutable i = 0 + + composedSource.ForEach (fun _ -> + { new SeqComposer.SeqConsumer<'T,'T> () with + override this.ProcessNext value = + f.Invoke(i, value) + i <- i + 1 + true }) + |> ignore [] - let exists f (source:seq<'T>) = - Composer.Seq.exists f (toComposer source) + let exists f (source : seq<'T>) = + let exists = + source + |> toComposer + |> foreach (fun pipeline -> + { new SeqComposer.AccumulatingConsumer<'T, bool> (false) with + override this.ProcessNext value = + if this.Accumulator then + pipeline.StopFurtherProcessing() + false + else + this.Accumulator <- f value + true + }) + exists.Accumulator [] - let inline contains element (source:seq<'T>) = - Composer.Seq.contains element (toComposer source) + let inline contains element (source : seq<'T>) = + let contains = + source + |> toComposer + |> foreach (fun pipeline -> + { new SeqComposer.AccumulatingConsumer<'T, bool> (false) with + override this.ProcessNext value = + if this.Accumulator then + pipeline.StopFurtherProcessing() + false + else + this.Accumulator <- element = value + true + }) + contains.Accumulator [] - let forall f (source:seq<'T>) = - Composer.Seq.forall f (toComposer source) + let forall f (source : seq<'T>) = + let forall = + source + |> toComposer + |> foreach (fun pipeline -> + { new SeqComposer.AccumulatingConsumer<'T, bool> (true) with + override this.ProcessNext value = + if this.Accumulator then + this.Accumulator <- f value + false + else + pipeline.StopFurtherProcessing() + true + }) + forall.Accumulator [] let iter2 f (source1 : seq<_>) (source2 : seq<_>) = @@ -1686,7 +1740,20 @@ namespace Microsoft.FSharp.Collections [] let tryPick f (source : seq<'T>) = - Composer.Seq.tryPick f (toComposer source) + let pick = + source + |> toComposer + |> foreach (fun pipeline -> + { new SeqComposer.AccumulatingConsumer<'T, Option<'U>> (None) with + override this.ProcessNext value = + if this.Accumulator.IsNone then + this.Accumulator <- f value + true + else + pipeline.StopFurtherProcessing() + false + }) + pick.Accumulator [] let pick f source = @@ -1696,7 +1763,21 @@ namespace Microsoft.FSharp.Collections [] let tryFind f (source : seq<'T>) = - Composer.Seq.tryFind f (toComposer source) + let find = + source + |> toComposer + |> foreach (fun pipeline -> + { new SeqComposer.AccumulatingConsumer<'T, Option<'T>> (None) with + override this.ProcessNext value = + if this.Accumulator.IsNone then + if f value then + this.Accumulator <- Some(value) + true + else + pipeline.StopFurtherProcessing() + false + }) + find.Accumulator [] let find f source = @@ -1743,24 +1824,15 @@ namespace Microsoft.FSharp.Collections [] let fold<'T,'State> f (x:'State) (source:seq<'T>) = - checkNonNull "source" source - match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let total = - s.ForEach (fun _ -> + let composedSource = toComposer source + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) + + let total = composedSource.ForEach (fun _ -> { new SeqComposer.AccumulatingConsumer<'T,'State> (x) with override this.ProcessNext value = this.Accumulator <- f.Invoke (this.Accumulator, value) true }) - total.Accumulator - | _ -> - use e = source.GetEnumerator() - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let mutable state = x - while e.MoveNext() do - state <- f.Invoke(state, e.Current) - state + total.Accumulator source |> foreach (fun _ -> @@ -1790,24 +1862,25 @@ namespace Microsoft.FSharp.Collections [] let reduce f (source : seq<'T>) = + let composedSource = toComposer source let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) + let mutable first = true - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value - else - this.Value._2 <- f.Invoke (this.Value._2, value) - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - - member this.OnComplete _ = - if this.Value._1 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun reduced -> reduced.Value._2 + let total = composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + if first then + first <- false + this.Accumulator <- value + else + this.Accumulator <- f.Invoke (this.Accumulator, value) + true + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if first then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + total.Accumulator [] let replicate count x = @@ -2178,17 +2251,6 @@ namespace Microsoft.FSharp.Collections then mkDelayedSeq (fun () -> countByValueType keyf source) else mkDelayedSeq (fun () -> countByRefType keyf source) - [] - let toComposer (source:seq<'T>): SeqComposer.SeqEnumerable<'T> = - checkNonNull "source" source - match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> upcast s - | :? array<'T> as a -> upcast SeqComposer.Array.Enumerable((fun () -> a), SeqComposer.IdentityFactory.IdentityFactory) - | :? list<'T> as a -> upcast SeqComposer.List.Enumerable(a, SeqComposer.IdentityFactory.IdentityFactory) - | _ -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(source, SeqComposer.IdentityFactory.IdentityFactory) - - let inline foreach f (source:SeqComposer.SeqEnumerable<_>) = source.ForEach f - [] let inline sum (source:seq<'a>) : 'a = let composedSource = toComposer source @@ -2444,6 +2506,24 @@ namespace Microsoft.FSharp.Collections [] let tail (source: seq<'T>) = source |> seqFactory (SeqComposer.TailFactory ()) + + [] + let tryLast (source : seq<_>) = + let composedSource = toComposer source + let mutable first = true + + let last = + composedSource.ForEach (fun _ -> + { new SeqComposer.AccumulatingConsumer<'T, 'T> (Unchecked.defaultof<'T>) with + override this.ProcessNext value = + if first then + first <- false + this.Accumulator <- value + true }) + if first then + None + else + Some(last.Accumulator) [] let last (source : seq<_>) = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index 443286c3fa0..98e95484c77 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -1155,16 +1155,6 @@ namespace Microsoft.FSharp.Collections [] val inline sortByDescending : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> when 'Key : comparison - /// Builds an SeqEnumerable from the given collection. - /// - /// The input sequence. - /// - /// The result SeqEnumerable. - /// - /// Thrown when the input sequence is null. - [] - val toComposer : source:seq<'T> -> SeqComposer.SeqEnumerable<'T> - /// Returns the sum of the elements in the sequence. /// /// The elements are summed using the + operator and Zero property associated with the generated type. @@ -1248,7 +1238,7 @@ namespace Microsoft.FSharp.Collections /// /// Thrown when the input sequence is null. [] - val toComposer : source:seq<'T> -> Composer.Core.ISeq<'T> + val toComposer : source:seq<'T> -> SeqComposer.SeqEnumerable<'T> /// Builds a list from the given collection. /// From ada1435c5360c286e58aa194a5caf25d8c741bf7 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Fri, 21 Oct 2016 04:36:33 +0200 Subject: [PATCH 41/59] Made names a little less verbose Fixed tryPick Processed 1 past the end of the data, as demo'd here: seq { for i = 1 to 5 do yield i failwith "boom" } |> Seq.pick (fun x -> if x = 5 then Some true else None) |> fun result -> assert result Fixed tryFind, similar to tryPick Error seen with seq { for i = 1 to 5 do yield i failwith "boom" } |> Seq.find (fun x -> x = 5) |> fun result -> assert (result=5) cleaned up math functions Just fixing some more one past the end more consistency more consistency foreach now takes seq and calls toComposer Made ignoring return value a bit more explicit processNextInForeach was a bit verbose Consolidated ForEach functionality Seq.concat --- src/fsharp/FSharp.Core/seq.fs | 753 +++++++++++++++------------------ src/fsharp/FSharp.Core/seq.fsi | 19 +- 2 files changed, 362 insertions(+), 410 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 91f55e81e26..35bfe316e5e 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -164,7 +164,7 @@ namespace Microsoft.FSharp.Core.CompilerServices member x.GetEnumerator() = f() interface IEnumerable with member x.GetEnumerator() = (f() :> IEnumerator) } - + [] type EmptyEnumerable<'T> = | EmptyEnumerable @@ -472,7 +472,7 @@ namespace Microsoft.FSharp.Collections member __.OnDispose() = () [] - type MutableData<'a,'b> = + type Values<'a,'b> = val mutable _1 : 'a val mutable _2 : 'b @@ -481,15 +481,27 @@ namespace Microsoft.FSharp.Collections _2 = b } + [] + type Values<'a,'b,'c> = + val mutable _1 : 'a + val mutable _2 : 'b + val mutable _3 : 'c + + new (a:'a, b:'b, c:'c) = { + _1 = a + _2 = b + _3 = c + } + [] - type AccumulatingConsumer<'T, 'U> = + type Folder<'T, 'U> = inherit SeqConsumer<'T,'T> - val mutable Accumulator : 'U + val mutable Value : 'U - new (initialState) = { + new (init) = { inherit SeqConsumer<'T,'T>() - Accumulator = initialState + Value = init } [] @@ -945,7 +957,84 @@ namespace Microsoft.FSharp.Collections interface ISeqPipeline with member x.StopFurtherProcessing() = halted <- true member __.Halted = halted + module ForEach = + let enumerable (enumerable:IEnumerable<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + use enumerator = enumerable.GetEnumerator () + while (not pipeline.Halted) && (enumerator.MoveNext ()) do + consumer.ProcessNext enumerator.Current |> ignore + + let array (array:array<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let mutable idx = 0 + while (not pipeline.Halted) && (idx < array.Length) do + consumer.ProcessNext array.[idx] |> ignore + idx <- idx + 1 + + let list (alist:list<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let rec iterate lst = + match pipeline.Halted, lst with + | true, _ + | false, [] -> () + | false, hd :: tl -> + consumer.ProcessNext hd |> ignore + iterate tl + iterate alist + + let unfold (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let rec iterate current = + match pipeline.Halted, generator current with + | true, _ + | false, None -> () + | false, Some (item, next) -> + consumer.ProcessNext item |> ignore + iterate next + + iterate state + + let makeIsSkipping (consumer:SeqConsumer<'T,'U>) = + match consumer with + | :? SeqComponent<'T,'U> as c -> c.Skipping + | _ -> fun () -> false + + let init f (terminatingIdx:int) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let mutable idx = -1 + let isSkipping = makeIsSkipping consumer + let mutable maybeSkipping = true + while (not pipeline.Halted) && (idx < terminatingIdx) do + if maybeSkipping then + maybeSkipping <- isSkipping () + + if (not maybeSkipping) then + consumer.ProcessNext (f (idx+1)) |> ignore + + idx <- idx + 1 + + let execute (f:ISeqPipeline->#SeqConsumer<'U,'U>) (current:SeqComponentFactory<'T,'U>) executeOn = + let pipeline = Pipeline() + let result = f pipeline + let consumer = current.Create pipeline result + try + executeOn pipeline consumer + (Helpers.upcastISeqComponent consumer).OnComplete () + result + finally + (Helpers.upcastISeqComponent consumer).OnDispose () + module Enumerable = + type Empty<'T>() = + let current () = failwith "library implementation error: Current should never be called" + interface IEnumerator<'T> with + member __.Current = current () + interface IEnumerator with + member __.Current = current () + member __.MoveNext () = false + member __.Reset (): unit = noReset () + interface IDisposable with + member __.Dispose () = () + + type EmptyEnumerators<'T>() = + static let element : IEnumerator<'T> = upcast (new Empty<'T> ()) + static member Element = element + [] type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ISeqComponent) = interface IDisposable with @@ -1013,10 +1102,6 @@ namespace Microsoft.FSharp.Collections and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqComponentFactory<'T,'U>) = inherit EnumerableBase<'U>() - static let iterate (enumerator:IEnumerator<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = - while (not pipeline.Halted) && (enumerator.MoveNext ()) do - consumer.ProcessNext enumerator.Current |> ignore - interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1026,35 +1111,27 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let pipeline = Pipeline() - let result = f pipeline - let consumer = current.Create pipeline result - use enumerator = enumerable.GetEnumerator () - try - iterate enumerator pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () - - and AppendEnumerator<'T> (sources:list>) = - let sources = sources |> List.rev + ForEach.execute f current (ForEach.enumerable enumerable) + and ConcatEnumerator<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = let mutable state = SeqProcessNextStates.NotStarted - let mutable remaining = sources.Tail - let mutable active = sources.Head.GetEnumerator () + let main = sources.GetEnumerator () + + let mutable active = + if main.MoveNext () + then main.Current.GetEnumerator () + else EmptyEnumerators.Element let rec moveNext () = - if active.MoveNext () then true + if active.MoveNext () then + true + elif main.MoveNext () then + active.Dispose () + active <- main.Current.GetEnumerator () + moveNext () else - match remaining with - | [] -> false - | hd :: tl -> - active.Dispose () - active <- hd.GetEnumerator () - remaining <- tl - - moveNext () + state <- SeqProcessNextStates.Finished + false interface IEnumerator<'T> with member __.Current = @@ -1074,18 +1151,15 @@ namespace Microsoft.FSharp.Collections interface IDisposable with member __.Dispose() = + main.Dispose () active.Dispose () and AppendEnumerable<'T> (sources:list>) = inherit EnumerableBase<'T>() - static let iterate (enumerator:IEnumerator<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = - while (not pipeline.Halted) && (enumerator.MoveNext ()) do - consumer.ProcessNext enumerator.Current |> ignore - interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = - Helpers.upcastEnumerator (new AppendEnumerator<_> (sources)) + Helpers.upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = Helpers.upcastEnumerable (Enumerable<'T,'V>(this, next)) @@ -1094,17 +1168,20 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = - let pipeline = Pipeline() - let result = f pipeline - let consumer : SeqConsumer<'T,'T> = upcast result - let enumerable = Helpers.upcastEnumerable (AppendEnumerable sources) - use enumerator = enumerable.GetEnumerator () - try - iterate enumerator pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () + ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable this) + + and ConcatEnumerable<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = + inherit EnumerableBase<'T>() + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = + Helpers.upcastEnumerator (new ConcatEnumerator<_,_> (sources)) + + override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = + Helpers.upcastEnumerable (Enumerable<'T,'V>(this, next)) + + override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = + ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable this) let create enumerable current = Helpers.upcastEnumerable (Enumerable(enumerable, current)) @@ -1144,12 +1221,6 @@ namespace Microsoft.FSharp.Collections type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() - static let iterate (array:array<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = - let mutable idx = 0 - while (not pipeline.Halted) && (idx < array.Length) do - consumer.ProcessNext array.[idx] |> ignore - idx <- idx + 1 - interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1159,15 +1230,7 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let pipeline = Pipeline () - let result = f pipeline - let consumer = current.Create pipeline result - try - iterate (delayedArray ()) pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () + ForEach.execute f current (ForEach.array (delayedArray ())) let createDelayed (delayedArray:unit->array<'T>) (current:SeqComponentFactory<'T,'U>) = Helpers.upcastEnumerable (Enumerable(delayedArray, current)) @@ -1205,16 +1268,6 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext list - let iterate (alist:list<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = - let rec iterate lst = - match pipeline.Halted, lst with - | true, _ - | false, [] -> () - | false, hd :: tl -> - consumer.ProcessNext hd |> ignore - iterate tl - iterate alist - type Enumerable<'T,'U>(alist:list<'T>, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() @@ -1227,15 +1280,7 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let pipeline = Pipeline () - let result = f pipeline - let consumer = current.Create pipeline result - try - iterate alist pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () + ForEach.execute f current (ForEach.list alist) let create alist current = Helpers.upcastEnumerable (Enumerable(alist, current)) @@ -1265,17 +1310,6 @@ namespace Microsoft.FSharp.Collections type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() - static let iterate (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = - let rec iterate current = - match pipeline.Halted, generator current with - | true, _ - | false, None -> () - | false, Some (item, next) -> - consumer.ProcessNext item |> ignore - iterate next - - iterate state - interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1285,15 +1319,7 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = - let pipeline = Pipeline () - let result = f pipeline - let consumer = current.Create pipeline result - try - iterate generator state pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () + ForEach.execute f current (ForEach.unfold generator state) module Init = // The original implementation of "init" delayed the calculation of Current, and so it was possible @@ -1315,16 +1341,11 @@ namespace Microsoft.FSharp.Collections else System.Int32.MaxValue - let makeIsSkipping (consumer:SeqConsumer<'T,'U>) = - match consumer with - | :? SeqComponent<'T,'U> as c -> c.Skipping - | _ -> fun () -> false - type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:SeqConsumer<'T,'U>, signal:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) let isSkipping = - makeIsSkipping seqComponent + ForEach.makeIsSkipping seqComponent let terminatingIdx = getTerminatingIdx count @@ -1362,18 +1383,6 @@ namespace Microsoft.FSharp.Collections type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqComponentFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() - static let iterate f (terminatingIdx:int) (isSkipping) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = - let mutable idx = -1 - let mutable maybeSkipping = true - while (not pipeline.Halted) && (idx < terminatingIdx) do - if maybeSkipping then - maybeSkipping <- isSkipping () - - if (not maybeSkipping) then - consumer.ProcessNext (f (idx+1)) |> ignore - - idx <- idx + 1 - interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () @@ -1383,17 +1392,8 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) override this.ForEach (createResult:ISeqPipeline->#SeqConsumer<'U,'U>) = - let pipeline = Pipeline () - let result = createResult pipeline - let consumer = current.Create pipeline result let terminatingIdx = getTerminatingIdx count - let isSkipping = makeIsSkipping consumer - try - iterate f terminatingIdx isSkipping pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () + ForEach.execute createResult current (ForEach.init f terminatingIdx) let upto lastOption f = match lastOption with @@ -1448,10 +1448,6 @@ namespace Microsoft.FSharp.Collections type EnumerableDecider<'T>(count:Nullable, f:int->'T) = inherit Enumerable.EnumerableBase<'T>() - static let iterate (enumerator:IEnumerator<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'T>) = - while (not pipeline.Halted) && (enumerator.MoveNext ()) do - consumer.ProcessNext enumerator.Current |> ignore - interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = // we defer back to the original implementation as, as it's quite idiomatic in it's decision @@ -1463,16 +1459,7 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = - let pipeline = Pipeline () - let result = f pipeline - let consumer : SeqConsumer<'T,'T> = upcast result - use enumerator = (Helpers.upcastEnumerable this).GetEnumerator () - try - iterate enumerator pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () - result - finally - (Helpers.upcastISeqComponent consumer).OnDispose () + ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable (Helpers.upcastEnumerable this)) #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions @@ -1490,7 +1477,10 @@ namespace Microsoft.FSharp.Collections | :? list<'T> as a -> upcast SeqComposer.List.Enumerable(a, SeqComposer.IdentityFactory.IdentityFactory) | _ -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(source, SeqComposer.IdentityFactory.IdentityFactory) - let inline foreach f (source:SeqComposer.SeqEnumerable<_>) = source.ForEach f + let inline foreach f (source:seq<_>) = + source + |> toComposer + |> fun composer -> composer.ForEach f let inline foreach f (source:seq<_>) = Composer.Seq.foreach f (toComposer source) @@ -1526,11 +1516,11 @@ namespace Microsoft.FSharp.Collections [] let iter f (source : seq<'T>) = source - |> toComposer |> foreach (fun _ -> { new SeqComposer.SeqConsumer<'T,'T> () with override this.ProcessNext value = - f value; true }) + f value + Unchecked.defaultof }) |> ignore [] @@ -1562,69 +1552,54 @@ namespace Microsoft.FSharp.Collections [] let iteri f (source : seq<'T>) = - let composedSource = toComposer source - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let mutable i = 0 - - composedSource.ForEach (fun _ -> - { new SeqComposer.SeqConsumer<'T,'T> () with - override this.ProcessNext value = - f.Invoke(i, value) - i <- i + 1 - true }) + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T, int> (0) with + override this.ProcessNext value = + f.Invoke(this.Value, value) + this.Value <- this.Value + 1 + Unchecked.defaultof }) |> ignore [] let exists f (source : seq<'T>) = - let exists = - source - |> toComposer - |> foreach (fun pipeline -> - { new SeqComposer.AccumulatingConsumer<'T, bool> (false) with - override this.ProcessNext value = - if this.Accumulator then - pipeline.StopFurtherProcessing() - false - else - this.Accumulator <- f value - true - }) - exists.Accumulator + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, bool> (false) with + override this.ProcessNext value = + if f value then + this.Value <- true + pipeline.StopFurtherProcessing () + Unchecked.defaultof + }) + |> fun exists -> exists.Value [] let inline contains element (source : seq<'T>) = - let contains = - source - |> toComposer - |> foreach (fun pipeline -> - { new SeqComposer.AccumulatingConsumer<'T, bool> (false) with - override this.ProcessNext value = - if this.Accumulator then - pipeline.StopFurtherProcessing() - false - else - this.Accumulator <- element = value - true - }) - contains.Accumulator + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, bool> (false) with + override this.ProcessNext value = + if element = value then + this.Value <- true + pipeline.StopFurtherProcessing() + Unchecked.defaultof + }) + |> fun contains -> contains.Value [] let forall f (source : seq<'T>) = - let forall = - source - |> toComposer - |> foreach (fun pipeline -> - { new SeqComposer.AccumulatingConsumer<'T, bool> (true) with - override this.ProcessNext value = - if this.Accumulator then - this.Accumulator <- f value - false - else - pipeline.StopFurtherProcessing() - true - }) - forall.Accumulator + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, bool> (true) with + override this.ProcessNext value = + if not (f value) then + this.Value <- false + pipeline.StopFurtherProcessing() + Unchecked.defaultof + }) + |> fun forall -> forall.Value [] let iter2 f (source1 : seq<_>) (source2 : seq<_>) = @@ -1740,20 +1715,17 @@ namespace Microsoft.FSharp.Collections [] let tryPick f (source : seq<'T>) = - let pick = - source - |> toComposer - |> foreach (fun pipeline -> - { new SeqComposer.AccumulatingConsumer<'T, Option<'U>> (None) with - override this.ProcessNext value = - if this.Accumulator.IsNone then - this.Accumulator <- f value - true - else - pipeline.StopFurtherProcessing() - false - }) - pick.Accumulator + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, Option<'U>> (None) with + override this.ProcessNext value = + match f value with + | (Some _) as some -> + this.Value <- some + pipeline.StopFurtherProcessing() + | None -> () + Unchecked.defaultof }) + |> fun pick -> pick.Value [] let pick f source = @@ -1763,21 +1735,15 @@ namespace Microsoft.FSharp.Collections [] let tryFind f (source : seq<'T>) = - let find = - source - |> toComposer - |> foreach (fun pipeline -> - { new SeqComposer.AccumulatingConsumer<'T, Option<'T>> (None) with - override this.ProcessNext value = - if this.Accumulator.IsNone then - if f value then - this.Accumulator <- Some(value) - true - else - pipeline.StopFurtherProcessing() - false - }) - find.Accumulator + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, Option<'T>> (None) with + override this.ProcessNext value = + if f value then + this.Value <- Some value + pipeline.StopFurtherProcessing() + Unchecked.defaultof }) + |> fun find -> find.Value [] let find f source = @@ -1806,7 +1772,7 @@ namespace Microsoft.FSharp.Collections [] let concat (sources:seq<#seq<'T>>) : seq<'T> = checkNonNull "sources" sources - upcast Composer.Seq.Enumerable.ConcatEnumerable sources + upcast SeqComposer.Enumerable.ConcatEnumerable sources [] let length (source : seq<'T>) = @@ -1824,15 +1790,15 @@ namespace Microsoft.FSharp.Collections [] let fold<'T,'State> f (x:'State) (source:seq<'T>) = - let composedSource = toComposer source let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let total = composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'State> (x) with - override this.ProcessNext value = - this.Accumulator <- f.Invoke (this.Accumulator, value) - true }) - total.Accumulator + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,'State> (x) with + override this.ProcessNext value = + this.Value <- f.Invoke (this.Value, value) + Unchecked.defaultof }) + |> fun folded -> folded.Value source |> foreach (fun _ -> @@ -1862,25 +1828,25 @@ namespace Microsoft.FSharp.Collections [] let reduce f (source : seq<'T>) = - let composedSource = toComposer source let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let mutable first = true - - let total = composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = - if first then - first <- false - this.Accumulator <- value - else - this.Accumulator <- f.Invoke (this.Accumulator, value) - true - interface SeqComposer.ISeqComponent with - member this.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - total.Accumulator + + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T, SeqComposer.Values> (SeqComposer.Values<_,_>(true, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + else + this.Value._2 <- f.Invoke (this.Value._2, value) + Unchecked.defaultof + + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'T, SeqComposer.Values>).Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun reduced -> reduced.Value._2 [] let replicate count x = @@ -2253,62 +2219,54 @@ namespace Microsoft.FSharp.Collections [] let inline sum (source:seq<'a>) : 'a = - let composedSource = toComposer source - let total = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'a,'a> (LanguagePrimitives.GenericZero) with - override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator value - true }) - total.Accumulator + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'a,'a> (LanguagePrimitives.GenericZero) with + override this.ProcessNext value = + this.Value <- Checked.(+) this.Value value + Unchecked.defaultof }) + |> fun sum -> sum.Value [] let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U = - let composedSource = toComposer source - let total = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with - override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator (f value) - true }) - total.Accumulator + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + override this.ProcessNext value = + this.Value <- Checked.(+) this.Value (f value) + Unchecked.defaultof }) + |> fun sum -> sum.Value [] let inline average (source: seq< ^a>) : ^a = - let total = - source - |> toComposer - |> foreach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'a, SeqComposer.MutableData<'a, int>> (SeqComposer.MutableData(LanguagePrimitives.GenericZero, 0)) with - override this.ProcessNext value = - this.Accumulator._1 <- Checked.(+) this.Accumulator._1 value - this.Accumulator._2 <- this.Accumulator._2 + 1 - true - - interface SeqComposer.ISeqComponent with - member this.OnComplete() = - if (this:?>SeqComposer.AccumulatingConsumer<'a, SeqComposer.MutableData<'a, int>>).Accumulator._2 = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - LanguagePrimitives.DivideByInt< ^a> total.Accumulator._1 total.Accumulator._2 + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'a, SeqComposer.Values<'a, int>> (SeqComposer.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + override this.ProcessNext value = + this.Value._1 <- Checked.(+) this.Value._1 value + this.Value._2 <- this.Value._2 + 1 + Unchecked.defaultof + + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'a, SeqComposer.Values<'a, int>>).Value._2 = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) + |> fun total -> LanguagePrimitives.DivideByInt< ^a> total.Value._1 total.Value._2 [] let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = - let composedSource = toComposer source - let mutable count = 0 - let total = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with - override this.ProcessNext value = - this.Accumulator <- Checked.(+) this.Accumulator (f value) - count <- count + 1 - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if count = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - LanguagePrimitives.DivideByInt< ^U> total.Accumulator count + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,SeqComposer.Values<'U, int>> (SeqComposer.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + override this.ProcessNext value = + this.Value._1 <- Checked.(+) this.Value._1 (f value) + this.Value._2 <- this.Value._2 + 1 + Unchecked.defaultof + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'T,SeqComposer.Values<'U, int>>).Value._2 = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) + |> fun total -> LanguagePrimitives.DivideByInt< ^U> total.Value._1 total.Value._2 member this.OnComplete _ = if this.Value._2 = 0 then @@ -2317,53 +2275,47 @@ namespace Microsoft.FSharp.Collections [] let inline min (source: seq<_>) = - let composedSource = toComposer source + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_>(true, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + elif value < this.Value._2 then + this.Value._2 <- value + Unchecked.defaultof - let mutable first = true - let min = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = - if first then - first <- false - this.Accumulator <- value - elif value < this.Accumulator then - this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - min.Accumulator + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun min -> min.Value._2 [] let inline minBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - let composedSource = toComposer source - - let mutable first = true - let mutable acc = Unchecked.defaultof<'U> - let min = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = - let currValue = value - let curr = f currValue - if first then - first <- false - acc <- curr - this.Accumulator <- value - else - if curr < acc then - acc <- curr - this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - min.Accumulator + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + match this.Value._1, f value with + | true, valueU -> + this.Value._1 <- false + this.Value._2 <- valueU + this.Value._3 <- value + | false, valueU when valueU < this.Value._2 -> + this.Value._2 <- valueU + this.Value._3 <- value + | _ -> () + Unchecked.defaultof + + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun min -> min.Value._3 (* [] let inline minValBy (f : 'T -> 'U) (source: seq<'T>) : 'U = @@ -2383,54 +2335,47 @@ namespace Microsoft.FSharp.Collections *) [] let inline max (source: seq<_>) = - let composedSource = toComposer source + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_>(true, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + elif value > this.Value._2 then + this.Value._2 <- value + Unchecked.defaultof - let mutable first = true - let max = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = - if first then - first <- false - this.Accumulator <- value - else - if value > this.Accumulator then - this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - max.Accumulator + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun max -> max.Value._2 [] let inline maxBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - let composedSource = toComposer source - - let mutable first = true - let mutable acc = Unchecked.defaultof<'U> - let min = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T,'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = - let currValue = value - let curr = f currValue - if first then - first <- false - acc <- curr - this.Accumulator <- value - else - if curr > acc then - acc <- curr - this.Accumulator <- value - true - interface SeqComposer.ISeqComponent with - member __.OnComplete() = - if first then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - min.Accumulator + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + match this.Value._1, f value with + | true, valueU -> + this.Value._1 <- false + this.Value._2 <- valueU + this.Value._3 <- value + | false, valueU when valueU > this.Value._2 -> + this.Value._2 <- valueU + this.Value._3 <- value + | _ -> () + Unchecked.defaultof + + interface SeqComposer.ISeqComponent with + member this.OnComplete() = + if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun min -> min.Value._3 (* [] @@ -2509,21 +2454,19 @@ namespace Microsoft.FSharp.Collections [] let tryLast (source : seq<_>) = - let composedSource = toComposer source - let mutable first = true - - let last = - composedSource.ForEach (fun _ -> - { new SeqComposer.AccumulatingConsumer<'T, 'T> (Unchecked.defaultof<'T>) with - override this.ProcessNext value = - if first then - first <- false - this.Accumulator <- value - true }) - if first then - None - else - Some(last.Accumulator) + source + |> foreach (fun _ -> + { new SeqComposer.Folder<'T, SeqComposer.Values> (SeqComposer.Values(true, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + Unchecked.defaultof }) + |> fun tried -> + if tried.Value._1 then + None + else + Some tried.Value._2 [] let last (source : seq<_>) = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index 98e95484c77..9c1c0413e19 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -28,19 +28,28 @@ namespace Microsoft.FSharp.Collections interface ISeqComponent [] - type MutableData<'a,'b> = + type Values<'a,'b> = struct - new : a:'a * b:'b -> MutableData<'a,'b> + new : a:'a * b:'b -> Values<'a,'b> val mutable _1: 'a val mutable _2: 'b end + [] + type Values<'a,'b,'c> = + struct + new : a:'a * b:'b * c:'c -> Values<'a,'b,'c> + val mutable _1: 'a + val mutable _2: 'b + val mutable _3: 'c + end + [] - type AccumulatingConsumer<'T,'U> = + type Folder<'T,'U> = class inherit SeqConsumer<'T,'T> - new : initialState:'U -> AccumulatingConsumer<'T,'U> - val mutable Accumulator: 'U + new : init:'U -> Folder<'T,'U> + val mutable Value: 'U end [] From 807121c186ce5bec2e5c62191a7a2a0acfc8f7ec Mon Sep 17 00:00:00 2001 From: liboz Date: Sat, 22 Oct 2016 13:29:55 +0200 Subject: [PATCH 42/59] findIndex/tryFindIndex fix bug with Concat when there are side effects --- src/fsharp/FSharp.Core/seq.fs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 35bfe316e5e..4631006915a 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -1117,10 +1117,7 @@ namespace Microsoft.FSharp.Collections let mutable state = SeqProcessNextStates.NotStarted let main = sources.GetEnumerator () - let mutable active = - if main.MoveNext () - then main.Current.GetEnumerator () - else EmptyEnumerators.Element + let mutable active = EmptyEnumerators.Element let rec moveNext () = if active.MoveNext () then @@ -1989,15 +1986,16 @@ namespace Microsoft.FSharp.Collections [] let tryFindIndex p (source:seq<_>) = source - |> foreach (fun halt -> - { new Composer.Core.Folder<'T, Composer.Core.Values, int>> (Composer.Core.Values<_,_>(None, 0)) with + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, SeqComposer.Values, int>> (SeqComposer.Values<_,_>(None, 0)) with override this.ProcessNext value = if p value then this.Value._1 <- Some(this.Value._2) - halt () + pipeline.StopFurtherProcessing() else this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + Unchecked.defaultof + }) |> fun tried -> tried.Value._1 [] From 45a64e64fbfd256ad2675249df6248c773dc3bc7 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sun, 23 Oct 2016 10:30:44 +0200 Subject: [PATCH 43/59] Fix a Take bug The following caused an exception, when it shouldn't: [1;2;3] |> Seq.take 100 |> Seq.takeWhile (fun _ -> false) |> Seq.iter (fun _ -> ()) I'm not 100% happy with how I'm allocating ids, nor really with the added ceremony of the solution, but I think the idea of how to resolve is basically the right one. Seq.scan Seq.tryItem, tryHead, head, exactlyOne --- src/fsharp/FSharp.Core/seq.fs | 349 ++++++++++++++++++--------------- src/fsharp/FSharp.Core/seq.fsi | 4 +- 2 files changed, 192 insertions(+), 161 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 4631006915a..ee553cff95f 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -457,18 +457,18 @@ namespace Microsoft.FSharp.Collections open IEnumerator type ISeqComponent = - abstract OnComplete : unit -> unit + abstract OnComplete : int -> unit abstract OnDispose : unit -> unit type ISeqPipeline = - abstract StopFurtherProcessing : unit -> unit + abstract StopFurtherProcessing : int -> unit [] type SeqConsumer<'T,'U> () = abstract ProcessNext : input:'T -> bool interface ISeqComponent with - member __.OnComplete() = () + member __.OnComplete _ = () member __.OnDispose() = () [] @@ -523,133 +523,139 @@ namespace Microsoft.FSharp.Collections let seqComponentTail = { new ISeqComponent with - member __.OnComplete() = () + member __.OnComplete _ = () member __.OnDispose() = () } type [] SeqComponentFactory<'T,'U> () = - abstract Create<'V> : ISeqPipeline -> SeqConsumer<'U,'V> -> SeqConsumer<'T,'V> + abstract Create<'V> : ISeqPipeline -> SeqConsumer<'U,'V> -> haltingIdx:int -> SeqConsumer<'T,'V> and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>) = inherit SeqComponentFactory<'T,'V> () - override __.Create<'W> (result:ISeqPipeline) (next:SeqConsumer<'V,'W>) : SeqConsumer<'T,'W> = - first.Create result (second.Create result next) + override __.Create<'W> (result:ISeqPipeline) (next:SeqConsumer<'V,'W>) (haltingIdx:int) : SeqConsumer<'T,'W> = + first.Create result (second.Create result next (haltingIdx+1)) (haltingIdx+2) static member Combine (first:SeqComponentFactory<'T,'U>) (second:SeqComponentFactory<'U,'V>) : SeqComponentFactory<'T,'V> = upcast ComposedFactory(first, second) and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = upcast Choose (filter, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Choose (filter, next, haltingIdx) and DistinctFactory<'T when 'T: equality> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Distinct (next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Distinct (next, haltingIdx) and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast DistinctBy (keyFunction, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast DistinctBy (keyFunction, next, haltingIdx) and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Except (itemsToExclude, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Except (itemsToExclude, next, haltingIdx) and FilterFactory<'T> (filter:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = match next with - | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter - | _ -> upcast Filter (filter, next) + | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter haltingIdx + | _ -> upcast Filter (filter, next, haltingIdx) and IdentityFactory<'T> () = inherit SeqComponentFactory<'T,'T> () static let singleton = IdentityFactory<'T>() - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = next + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (_haltingIdx:int) : SeqConsumer<'T,'V> = next static member IdentityFactory = singleton and MapFactory<'T,'U> (map:'T->'U) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = match next with - | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map - | _ -> upcast Map<_,_,_> (map, next) + | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map haltingIdx + | _ -> upcast Map<_,_,_> (map, next, haltingIdx) and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'First,'V> = upcast Map2First (map, input2, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'First,'V> = upcast Map2First (map, input2, result, next, haltingIdx) and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = inherit SeqComponentFactory<'Second,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'Second,'V> = upcast Map2Second (map, input1, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'Second,'V> = upcast Map2Second (map, input1, result, next, haltingIdx) and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'First,'V> = upcast Map3 (map, input2, input3, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'First,'V> = upcast Map3 (map, input2, input3, result, next, haltingIdx) and MapiFactory<'T,'U> (mapi:int->'T->'U) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'T,'V> = upcast Mapi (mapi, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Mapi (mapi, next, haltingIdx) and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) : SeqConsumer<'First,'V> = upcast Mapi2 (map, input2, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'First,'V> = upcast Mapi2 (map, input2, result, next, haltingIdx) and PairwiseFactory<'T> () = inherit SeqComponentFactory<'T,'T*'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T*'T,'V>) : SeqConsumer<'T,'V> = upcast Pairwise next + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T*'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Pairwise (next, haltingIdx) + + and ScanFactory<'T,'State> (folder:'State->'T->'State, initialState:'State) = + inherit SeqComponentFactory<'T,'State> () + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'State,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next, haltingIdx) and SkipFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Skip (count, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Skip (count, next, haltingIdx) and SkipWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast SkipWhile (predicate, next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast SkipWhile (predicate, next, haltingIdx) and TakeWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast TakeWhile (predicate, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast TakeWhile (predicate, result, next, haltingIdx) and TakeFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Take (count, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Take (count, result, next, haltingIdx) and TailFactory<'T> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Tail<'T,'V> (next) + override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Tail<'T,'V> (next, haltingIdx) and TruncateFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) : SeqConsumer<'T,'V> = upcast Truncate (count, result, next) + override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Truncate (count, result, next, haltingIdx) - and [] SeqComponent<'T,'U> (next:ISeqComponent) = + and [] SeqComponent<'T,'U> (next:ISeqComponent, haltingIdx:int) = inherit SeqConsumer<'T,'U>() // Seq.init(Infinite)? lazily uses Current. The only SeqComposer component that can do that is Skip // and it can only do it at the start of a sequence abstract Skipping : unit -> bool - abstract CreateMap<'S> : map:('S->'T) -> SeqComponent<'S,'U> - abstract CreateFilter : filter:('T->bool) -> SeqComponent<'T,'U> + abstract CreateMap<'S> : map:('S->'T) -> haltingIdx:int -> SeqComponent<'S,'U> + abstract CreateFilter : filter:('T->bool) -> haltingIdx:int -> SeqComponent<'T,'U> interface ISeqComponent with - member __.OnComplete () = next.OnComplete () + member __.OnComplete halted = next.OnComplete halted member __.OnDispose () = next.OnDispose () + member __.HaltingIdx = haltingIdx + default __.Skipping () = false - default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) - default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) + default this.CreateMap<'S> (map:'S->'T) (haltingIdx:int) = upcast Map<_,_,_> (map, this, haltingIdx) + default this.CreateFilter (filter:'T->bool) (haltingIdx:int) = upcast Filter (filter, this, haltingIdx) - and Choose<'T,'U,'V> (choose:'T->option<'U>, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) + and Choose<'T,'U,'V> (choose:'T->option<'U>, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) override __.ProcessNext (input:'T) : bool = match choose input with | Some value -> Helpers.avoidTailCall (next.ProcessNext value) | None -> false - and Distinct<'T,'V when 'T: equality> (next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Distinct<'T,'V when 'T: equality> (next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) @@ -659,8 +665,8 @@ namespace Microsoft.FSharp.Collections else false - and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) @@ -670,8 +676,8 @@ namespace Microsoft.FSharp.Collections else false - and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) @@ -681,10 +687,10 @@ namespace Microsoft.FSharp.Collections else false - and Filter<'T,'V> (filter:'T->bool, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Filter<'T,'V> (filter:'T->bool, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) - override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) + override this.CreateMap<'S> (map:'S->'T) (haltingIdx:int) = upcast MapThenFilter<_,_,_> (map, filter, next, haltingIdx) override __.ProcessNext (input:'T) : bool = if filter input then @@ -692,8 +698,8 @@ namespace Microsoft.FSharp.Collections else false - and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) + and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) override __.ProcessNext (input:'T) : bool = if filter input then @@ -701,16 +707,16 @@ namespace Microsoft.FSharp.Collections else false - and Map<'T,'U,'V> (map:'T->'U, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) + and Map<'T,'U,'V> (map:'T->'U, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) - override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) + override this.CreateFilter (filter:'T->bool) (haltingIdx:int) = upcast FilterThenMap (filter, map, next, haltingIdx) override __.ProcessNext (input:'T) : bool = Helpers.avoidTailCall (next.ProcessNext (map input)) - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'First,'V>(next) + and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'First,'V>(next, haltingIdx) let input2 = enumerable2.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map @@ -719,7 +725,7 @@ namespace Microsoft.FSharp.Collections if input2.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) else - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx false interface ISeqComponent with @@ -729,8 +735,8 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'Second,'V>(next) + and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'Second,'V>(next, haltingIdx) let input1 = enumerable1.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map @@ -739,7 +745,7 @@ namespace Microsoft.FSharp.Collections if input1.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) else - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx false interface ISeqComponent with @@ -749,8 +755,8 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'First,'V>(next) + and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'First,'V>(next, haltingIdx) let input2 = enumerable2.GetEnumerator () let input3 = enumerable3.GetEnumerator () @@ -760,7 +766,7 @@ namespace Microsoft.FSharp.Collections if input2.MoveNext () && input3.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) else - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx false interface ISeqComponent with @@ -773,8 +779,8 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) + and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) override __.ProcessNext (input:'T) : bool = let u = map input @@ -783,8 +789,8 @@ namespace Microsoft.FSharp.Collections else false - and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) + and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let mutable idx = 0 let mapi' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt mapi @@ -793,8 +799,8 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) - and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>) = - inherit SeqComponent<'First,'V>(next) + and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = + inherit SeqComponent<'First,'V>(next, haltingIdx) let mutable idx = 0 let input2 = enumerable2.GetEnumerator () @@ -805,7 +811,7 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) else - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx false interface ISeqComponent with @@ -815,8 +821,8 @@ namespace Microsoft.FSharp.Collections finally (Helpers.upcastISeqComponent next).OnDispose () - and Pairwise<'T,'V> (next:SeqConsumer<'T*'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Pairwise<'T,'V> (next:SeqConsumer<'T*'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let mutable isFirst = true let mutable lastValue = Unchecked.defaultof<'T> @@ -831,8 +837,18 @@ namespace Microsoft.FSharp.Collections lastValue <- input Helpers.avoidTailCall (next.ProcessNext currentPair) - and Skip<'T,'V> (skipCount:int, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:SeqConsumer<'State,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) + + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder + let mutable foldResult = initialState + + override __.ProcessNext (input:'T) : bool = + foldResult <- f.Invoke(foldResult, input) + Helpers.avoidTailCall (next.ProcessNext foldResult) + + and Skip<'T,'V> (skipCount:int, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let mutable count = 0 @@ -851,15 +867,15 @@ namespace Microsoft.FSharp.Collections Helpers.avoidTailCall (next.ProcessNext input) interface ISeqComponent with - override __.OnComplete () = + override __.OnComplete halted = if count < skipCount then let x = skipCount - count invalidOpFmt "tried to skip {0} {1} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - (Helpers.upcastISeqComponent next).OnComplete () + (Helpers.upcastISeqComponent next).OnComplete halted - and SkipWhile<'T,'V> (predicate:'T->bool, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and SkipWhile<'T,'V> (predicate:'T->bool, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let mutable skip = true @@ -873,29 +889,29 @@ namespace Microsoft.FSharp.Collections else Helpers.avoidTailCall (next.ProcessNext input) - and Take<'T,'V> (takeCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>) = - inherit Truncate<'T, 'V>(takeCount, result, next) + and Take<'T,'V> (takeCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit Truncate<'T, 'V>(takeCount, result, next, haltingIdx) interface ISeqComponent with - override this.OnComplete () = - if this.Count < takeCount then + override this.OnComplete halted = + if halted = 0 || halted > haltingIdx && this.Count < takeCount then let x = takeCount - this.Count invalidOpFmt "tried to take {0} {1} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - (Helpers.upcastISeqComponent next).OnComplete () + (Helpers.upcastISeqComponent next).OnComplete halted - and TakeWhile<'T,'V> (predicate:'T->bool, result:ISeqPipeline, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and TakeWhile<'T,'V> (predicate:'T->bool, result:ISeqPipeline, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) override __.ProcessNext (input:'T) : bool = if predicate input then Helpers.avoidTailCall (next.ProcessNext input) else - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx false - and Tail<'T, 'V> (next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Tail<'T, 'V> (next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let mutable first = true @@ -907,13 +923,13 @@ namespace Microsoft.FSharp.Collections Helpers.avoidTailCall (next.ProcessNext input) interface ISeqComponent with - override this.OnComplete () = + override this.OnComplete halted = if first then invalidArg "source" (SR.GetString(SR.notEnoughElements)) - (Helpers.upcastISeqComponent next).OnComplete () + (Helpers.upcastISeqComponent next).OnComplete halted - and Truncate<'T,'V> (truncateCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Truncate<'T,'V> (truncateCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>, haltingIdx:int) = + inherit SeqComponent<'T,'V>(next, haltingIdx) let mutable count = 0 @@ -923,10 +939,10 @@ namespace Microsoft.FSharp.Collections if count < truncateCount then count <- count + 1 if count = truncateCount then - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx next.ProcessNext input else - result.StopFurtherProcessing () + result.StopFurtherProcessing haltingIdx false type SeqProcessNextStates = @@ -935,14 +951,14 @@ namespace Microsoft.FSharp.Collections | Finished = 2 type Result<'T>() = - let mutable halted = false + let mutable haltedIdx = 0 member val Current = Unchecked.defaultof<'T> with get, set member val SeqState = SeqProcessNextStates.NotStarted with get, set - member __.Halted = halted + member __.Halted = haltedIdx interface ISeqPipeline with - member __.StopFurtherProcessing () = halted <- true + member __.StopFurtherProcessing haltingIdx = haltedIdx <- haltingIdx // SetResult<> is used at the end of the chain of SeqComponents to assign the final value type SetResult<'T> (result:Result<'T>) = @@ -953,40 +969,38 @@ namespace Microsoft.FSharp.Collections true type Pipeline() = - let mutable halted = false - interface ISeqPipeline with member x.StopFurtherProcessing() = halted <- true + let mutable halted = 0 + interface ISeqPipeline with member x.StopFurtherProcessing haltingIdx = halted <- haltingIdx member __.Halted = halted module ForEach = let enumerable (enumerable:IEnumerable<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = use enumerator = enumerable.GetEnumerator () - while (not pipeline.Halted) && (enumerator.MoveNext ()) do + while (pipeline.Halted = 0) && (enumerator.MoveNext ()) do consumer.ProcessNext enumerator.Current |> ignore let array (array:array<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = let mutable idx = 0 - while (not pipeline.Halted) && (idx < array.Length) do + while (pipeline.Halted = 0) && (idx < array.Length) do consumer.ProcessNext array.[idx] |> ignore idx <- idx + 1 let list (alist:list<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = let rec iterate lst = match pipeline.Halted, lst with - | true, _ - | false, [] -> () - | false, hd :: tl -> + | 0, hd :: tl -> consumer.ProcessNext hd |> ignore iterate tl + | _ -> () iterate alist let unfold (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = let rec iterate current = match pipeline.Halted, generator current with - | true, _ - | false, None -> () - | false, Some (item, next) -> + | 0, Some (item, next) -> consumer.ProcessNext item |> ignore iterate next + | _ -> () iterate state @@ -999,7 +1013,7 @@ namespace Microsoft.FSharp.Collections let mutable idx = -1 let isSkipping = makeIsSkipping consumer let mutable maybeSkipping = true - while (not pipeline.Halted) && (idx < terminatingIdx) do + while (pipeline.Halted = 0) && (idx < terminatingIdx) do if maybeSkipping then maybeSkipping <- isSkipping () @@ -1011,10 +1025,10 @@ namespace Microsoft.FSharp.Collections let execute (f:ISeqPipeline->#SeqConsumer<'U,'U>) (current:SeqComponentFactory<'T,'U>) executeOn = let pipeline = Pipeline() let result = f pipeline - let consumer = current.Create pipeline result + let consumer = current.Create pipeline result 1 try executeOn pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete () + (Helpers.upcastISeqComponent consumer).OnComplete pipeline.Halted result finally (Helpers.upcastISeqComponent consumer).OnDispose () @@ -1077,14 +1091,14 @@ namespace Microsoft.FSharp.Collections inherit EnumeratorBase<'U>(result, seqComponent) let rec moveNext () = - if (not result.Halted) && source.MoveNext () then + if (result.Halted = 0) && source.MoveNext () then if seqComponent.ProcessNext source.Current then true else moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete () + (Helpers.upcastISeqComponent seqComponent).OnComplete result.Halted false interface IEnumerator with @@ -1105,7 +1119,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (SetResult<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (SetResult<'U> result) 1, result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) @@ -1199,7 +1213,7 @@ namespace Microsoft.FSharp.Collections initMoveNext <- ignore let rec moveNext () = - if (not result.Halted) && idx < array.Length then + if (result.Halted = 0) && idx < array.Length then idx <- idx+1 if seqComponent.ProcessNext array.[idx-1] then true @@ -1207,7 +1221,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete () + (Helpers.upcastISeqComponent seqComponent).OnComplete result.Halted false interface IEnumerator with @@ -1221,7 +1235,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result (SetResult<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result (SetResult<'U> result) 1, result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) @@ -1249,7 +1263,7 @@ namespace Microsoft.FSharp.Collections let rec moveNext current = match result.Halted, current with - | false, head::tail -> + | 0, head::tail -> if seqComponent.ProcessNext head then list <- tail true @@ -1257,7 +1271,7 @@ namespace Microsoft.FSharp.Collections moveNext tail | _ -> result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete () + (Helpers.upcastISeqComponent seqComponent).OnComplete result.Halted false interface IEnumerator with @@ -1271,7 +1285,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (SetResult<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (SetResult<'U> result) 1, result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) @@ -1290,14 +1304,13 @@ namespace Microsoft.FSharp.Collections let rec moveNext () = match signal.Halted, generator current with - | true, _ - | false, None -> false - | false, Some (item, nextState) -> + | 0, Some (item, nextState) -> current <- nextState if seqComponent.ProcessNext item then true else moveNext () + | _ -> false interface IEnumerator with member __.MoveNext () = @@ -1310,7 +1323,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (SetResult<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (SetResult<'U> result) 1, result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) @@ -1351,7 +1364,7 @@ namespace Microsoft.FSharp.Collections let mutable idx = -1 let rec moveNext () = - if (not signal.Halted) && idx < terminatingIdx then + if (signal.Halted = 0) && idx < terminatingIdx then idx <- idx + 1 if maybeSkipping then @@ -1365,11 +1378,11 @@ namespace Microsoft.FSharp.Collections true else moveNext () - elif (not signal.Halted) && idx = System.Int32.MaxValue then + elif (signal.Halted = 0) && idx = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) else signal.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete () + (Helpers.upcastISeqComponent seqComponent).OnComplete signal.Halted false interface IEnumerator with @@ -1383,7 +1396,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (SetResult<'U> result), result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (SetResult<'U> result) 1, result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) @@ -1541,8 +1554,19 @@ namespace Microsoft.FSharp.Collections | Some value -> value [] - let tryItem i (source:seq<'T>) = - Composer.Seq.tryItem i (toComposer source) + let tryItem i (source : seq<'T>) = + if i < 0 then None else + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, SeqComposer.Values>> (SeqComposer.Values<_, _> (0, None)) with + override this.ProcessNext value = + if this.Value._1 = i then + this.Value._2 <- Some value + pipeline.StopFurtherProcessing 1 + else + this.Value._1 <- this.Value._1 + 1 + Unchecked.defaultof }) + |> fun item -> item.Value._2 [] let nth i (source : seq<'T>) = item i source @@ -1567,7 +1591,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = if f value then this.Value <- true - pipeline.StopFurtherProcessing () + pipeline.StopFurtherProcessing 1 Unchecked.defaultof }) |> fun exists -> exists.Value @@ -1580,7 +1604,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = if element = value then this.Value <- true - pipeline.StopFurtherProcessing() + pipeline.StopFurtherProcessing 1 Unchecked.defaultof }) |> fun contains -> contains.Value @@ -1593,7 +1617,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = if not (f value) then this.Value <- false - pipeline.StopFurtherProcessing() + pipeline.StopFurtherProcessing 1 Unchecked.defaultof }) |> fun forall -> forall.Value @@ -1719,7 +1743,7 @@ namespace Microsoft.FSharp.Collections match f value with | (Some _) as some -> this.Value <- some - pipeline.StopFurtherProcessing() + pipeline.StopFurtherProcessing 1 | None -> () Unchecked.defaultof }) |> fun pick -> pick.Value @@ -1738,7 +1762,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = if f value then this.Value <- Some value - pipeline.StopFurtherProcessing() + pipeline.StopFurtherProcessing 1 Unchecked.defaultof }) |> fun find -> find.Value @@ -1839,7 +1863,7 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'T, SeqComposer.Values>).Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -1962,8 +1986,8 @@ namespace Microsoft.FSharp.Collections [] let scan<'T,'State> f (z:'State) (source : seq<'T>): seq<'State> = let first = [|z|] :> IEnumerable<'State> - let rest = source |> seqFactory (Composer.Seq.ScanFactory (f, z)) - upcast Composer.Seq.Enumerable.ConcatEnumerable [|first; rest;|] + let rest = source |> seqFactory (SeqComposer.ScanFactory (f, z)) + upcast SeqComposer.Enumerable.ConcatEnumerable [|first; rest;|] [] let tryFindBack f (source : seq<'T>) = @@ -1991,7 +2015,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = if p value then this.Value._1 <- Some(this.Value._2) - pipeline.StopFurtherProcessing() + pipeline.StopFurtherProcessing 1 else this.Value._2 <- this.Value._2 + 1 Unchecked.defaultof @@ -2246,7 +2270,7 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'a, SeqComposer.Values<'a, int>>).Value._2 = 0 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun total -> LanguagePrimitives.DivideByInt< ^a> total.Value._1 total.Value._2 @@ -2261,7 +2285,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- this.Value._2 + 1 Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'T,SeqComposer.Values<'U, int>>).Value._2 = 0 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun total -> LanguagePrimitives.DivideByInt< ^U> total.Value._1 total.Value._2 @@ -2285,7 +2309,7 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -2309,7 +2333,7 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -2345,7 +2369,7 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -2369,7 +2393,7 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof interface SeqComposer.ISeqComponent with - member this.OnComplete() = + member this.OnComplete _ = if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -2407,25 +2431,23 @@ namespace Microsoft.FSharp.Collections use e2 = source2.GetEnumerator() let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(p) - source1 - |> foreach (fun halt -> - { new Composer.Core.Folder<_,bool> (true) with - override this.ProcessNext value = - if (e2.MoveNext()) then - if not (p.Invoke(value, e2.Current)) then - this.Value <- false - halt() - else - halt() - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun all -> all.Value - [] let exists2 p (source1: seq<_>) (source2: seq<_>) = checkNonNull "source2" source2 use e2 = source2.GetEnumerator() let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(p) + + [] + let tryHead (source : seq<_>) = + source + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, Option<'T>> (None) with + override this.ProcessNext value = + this.Value <- Some value + pipeline.StopFurtherProcessing 1 + Unchecked.defaultof }) + |> fun head -> head.Value source1 |> foreach (fun halt -> @@ -2475,16 +2497,25 @@ namespace Microsoft.FSharp.Collections [] let exactlyOne (source : seq<_>) = source - |> foreach (fun halt -> - { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values(true, Unchecked.defaultof<'T>, false)) with + |> foreach (fun pipeline -> + { new SeqComposer.Folder<'T, SeqComposer.Values> (SeqComposer.Values(true, Unchecked.defaultof<'T>, false)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false this.Value._2 <- value else this.Value._3 <- true - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + pipeline.StopFurtherProcessing 1 + Unchecked.defaultof + interface SeqComposer.ISeqComponent with + member this.OnComplete _ = + let value = (this:?>SeqComposer.Folder<'T,SeqComposer.Values>) + if value.Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + elif value.Value._3 then + invalidArg "source" (SR.GetString(SR.inputSequenceTooLong)) + }) + |> fun one -> one.Value._2 member this.OnComplete _ = if this.Value._1 then diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index 9c1c0413e19..b3fdc5639da 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -15,11 +15,11 @@ namespace Microsoft.FSharp.Collections module Seq = module SeqComposer = type ISeqComponent = - abstract OnComplete : unit -> unit + abstract OnComplete : int -> unit abstract OnDispose : unit -> unit type ISeqPipeline = - abstract StopFurtherProcessing : unit -> unit + abstract StopFurtherProcessing : int -> unit [] type SeqConsumer<'T,'U> = From 7e126debd8eaa40037b6d67a7e1a923f400b41aa Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Mon, 24 Oct 2016 11:17:12 +0200 Subject: [PATCH 44/59] Another take on halting index - Shrank public interface by removing ISeqPipeline from ForEach. - Renamed haltingIdx to pipelineDepth - Removed haltingIdx from where I could Remove mutable state in SeqComponentFactory - Changed "depth" to "idx" to better communicate the function Simplified use of OnComplete & OnDispose Pushed the chaining functionality into the interface and added extra methods on SeqConsumer. This means the consumer can ignore the interface and just implement their version, which means less likely to be an issue of the message not being chained correctly. It also has the advantage that in the object expressions we don't have to cast back to the base type, which was a potentital area for errors. Starting to finalise namespacing and comments Still playing around, happy for some input here... --- src/fsharp/FSharp.Core/seq.fs | 679 ++++++++++++++++----------------- src/fsharp/FSharp.Core/seq.fsi | 104 ++--- 2 files changed, 394 insertions(+), 389 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index ee553cff95f..3dfb9f9f3de 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -453,60 +453,79 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = - module SeqComposer = + module Composer = open IEnumerator - type ISeqComponent = - abstract OnComplete : int -> unit - abstract OnDispose : unit -> unit + module Internal = + type PipeIdx = int + type ``PipeIdx?`` = Nullable + let emptyPipeIdx = Nullable () + let inline getPipeIdx (maybePipeIdx:``PipeIdx?``) = if maybePipeIdx.HasValue then maybePipeIdx.Value else 1 + let inline makePipeIdx (pipeIdx:PipeIdx) = Nullable pipeIdx - type ISeqPipeline = - abstract StopFurtherProcessing : int -> unit + type ICompletionChaining = + abstract OnComplete : PipeIdx -> unit + abstract OnDispose : unit -> unit - [] - type SeqConsumer<'T,'U> () = - abstract ProcessNext : input:'T -> bool + type IPipeline = + abstract StopFurtherProcessing : PipeIdx -> unit - interface ISeqComponent with - member __.OnComplete _ = () - member __.OnDispose() = () + [] + type Consumer<'T,'U> () = + abstract ProcessNext : input:'T -> bool + + abstract OnComplete : PipeIdx -> unit + abstract OnDispose : unit -> unit + + default __.OnComplete _ = () + default __.OnDispose () = () + + interface ICompletionChaining with + member this.OnComplete terminatingIdx = + this.OnComplete terminatingIdx - [] - type Values<'a,'b> = - val mutable _1 : 'a - val mutable _2 : 'b + member this.OnDispose () = + try this.OnDispose () + finally () - new (a:'a, b: 'b) = { - _1 = a - _2 = b - } + [] + type Values<'a,'b> = + val mutable _1 : 'a + val mutable _2 : 'b - [] - type Values<'a,'b,'c> = - val mutable _1 : 'a - val mutable _2 : 'b - val mutable _3 : 'c + new (a:'a, b: 'b) = { + _1 = a + _2 = b + } - new (a:'a, b:'b, c:'c) = { - _1 = a - _2 = b - _3 = c - } + [] + type Values<'a,'b,'c> = + val mutable _1 : 'a + val mutable _2 : 'b + val mutable _3 : 'c + + new (a:'a, b:'b, c:'c) = { + _1 = a + _2 = b + _3 = c + } + + [] + type Folder<'T, 'U> = + inherit Consumer<'T,'T> - [] - type Folder<'T, 'U> = - inherit SeqConsumer<'T,'T> + val mutable Value : 'U - val mutable Value : 'U + new (init) = { + inherit Consumer<'T,'T>() + Value = init + } - new (init) = { - inherit SeqConsumer<'T,'T>() - Value = init - } + [] + type SeqEnumerable<'T>() = + abstract member ForEach<'a when 'a :> Consumer<'T,'T>> : f:((unit->unit)->'a) -> 'a - [] - type SeqEnumerable<'T>() = - abstract member ForEach<'a when 'a :> SeqConsumer<'T,'T>> : f:(ISeqPipeline->'a) -> 'a + open Internal module Helpers = // used for performance reasons; these are not recursive calls, so should be safe @@ -519,143 +538,145 @@ namespace Microsoft.FSharp.Collections let inline upcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) - let inline upcastISeqComponent (t:#ISeqComponent) : ISeqComponent = (# "" t : ISeqComponent #) + let inline upcastISeqComponent (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) + + type [] SeqComponentFactory<'T,'U> (pipeIdx:``PipeIdx?``) = + abstract Create<'V> : IPipeline -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> - let seqComponentTail = - { new ISeqComponent with - member __.OnComplete _ = () - member __.OnDispose() = () } + new() = SeqComponentFactory<'T,'U> (emptyPipeIdx) + + member __.PipeIdx = getPipeIdx pipeIdx - type [] SeqComponentFactory<'T,'U> () = - abstract Create<'V> : ISeqPipeline -> SeqConsumer<'U,'V> -> haltingIdx:int -> SeqConsumer<'T,'V> + and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>, secondPipeIdx:PipeIdx) = + inherit SeqComponentFactory<'T,'V> (makePipeIdx secondPipeIdx) - and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>) = - inherit SeqComponentFactory<'T,'V> () - override __.Create<'W> (result:ISeqPipeline) (next:SeqConsumer<'V,'W>) (haltingIdx:int) : SeqConsumer<'T,'W> = - first.Create result (second.Create result next (haltingIdx+1)) (haltingIdx+2) + override this.Create<'W> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'V,'W>) : Consumer<'T,'W> = + first.Create result pipeIdx (second.Create result (makePipeIdx secondPipeIdx) next) static member Combine (first:SeqComponentFactory<'T,'U>) (second:SeqComponentFactory<'U,'V>) : SeqComponentFactory<'T,'V> = - upcast ComposedFactory(first, second) + upcast ComposedFactory(first, second, first.PipeIdx+1) and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Choose (filter, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) and DistinctFactory<'T when 'T: equality> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Distinct (next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast DistinctBy (keyFunction, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Except (itemsToExclude, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) and FilterFactory<'T> (filter:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = match next with - | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter haltingIdx - | _ -> upcast Filter (filter, next, haltingIdx) + | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter + | _ -> upcast Filter (filter, next) and IdentityFactory<'T> () = inherit SeqComponentFactory<'T,'T> () static let singleton = IdentityFactory<'T>() - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (_haltingIdx:int) : SeqConsumer<'T,'V> = next + override __.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next static member IdentityFactory = singleton and MapFactory<'T,'U> (map:'T->'U) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = match next with - | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map haltingIdx - | _ -> upcast Map<_,_,_> (map, next, haltingIdx) + | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map + | _ -> upcast Map<_,_,_> (map, next) and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'First,'V> = upcast Map2First (map, input2, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, result, next, getPipeIdx pipeIdx) and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = inherit SeqComponentFactory<'Second,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'Second,'V> = upcast Map2Second (map, input1, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, result, next, getPipeIdx pipeIdx) and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'First,'V> = upcast Map3 (map, input2, input3, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, result, next, getPipeIdx pipeIdx) and MapiFactory<'T,'U> (mapi:int->'T->'U) = inherit SeqComponentFactory<'T,'U> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Mapi (mapi, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Mapi (mapi, next) and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'U,'V>) (haltingIdx:int) : SeqConsumer<'First,'V> = upcast Mapi2 (map, input2, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, result, next, getPipeIdx pipeIdx) and PairwiseFactory<'T> () = inherit SeqComponentFactory<'T,'T*'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T*'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Pairwise (next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) and ScanFactory<'T,'State> (folder:'State->'T->'State, initialState:'State) = inherit SeqComponentFactory<'T,'State> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'State,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) and SkipFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Skip (count, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, next) and SkipWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast SkipWhile (predicate, next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) and TakeWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast TakeWhile (predicate, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, result, next, getPipeIdx pipeIdx) and TakeFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Take (count, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, result, next, getPipeIdx pipeIdx) and TailFactory<'T> () = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (_result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Tail<'T,'V> (next, haltingIdx) + override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) and TruncateFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override __.Create<'V> (result:ISeqPipeline) (next:SeqConsumer<'T,'V>) (haltingIdx:int) : SeqConsumer<'T,'V> = upcast Truncate (count, result, next, haltingIdx) + override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, result, next, getPipeIdx pipeIdx) - and [] SeqComponent<'T,'U> (next:ISeqComponent, haltingIdx:int) = - inherit SeqConsumer<'T,'U>() + and [] SeqComponent<'T,'U> (next:ICompletionChaining) = + inherit Consumer<'T,'U>() - // Seq.init(Infinite)? lazily uses Current. The only SeqComposer component that can do that is Skip + // Seq.init(Infinite)? lazily uses Current. The only Composer component that can do that is Skip // and it can only do it at the start of a sequence abstract Skipping : unit -> bool - abstract CreateMap<'S> : map:('S->'T) -> haltingIdx:int -> SeqComponent<'S,'U> - abstract CreateFilter : filter:('T->bool) -> haltingIdx:int -> SeqComponent<'T,'U> - - interface ISeqComponent with - member __.OnComplete halted = next.OnComplete halted - member __.OnDispose () = next.OnDispose () + abstract CreateMap<'S> : map:('S->'T) -> SeqComponent<'S,'U> + abstract CreateFilter : filter:('T->bool) -> SeqComponent<'T,'U> - member __.HaltingIdx = haltingIdx + interface ICompletionChaining with + member this.OnComplete terminatingIdx = + this.OnComplete terminatingIdx + next.OnComplete terminatingIdx + member this.OnDispose () = + try this.OnDispose () + finally next.OnDispose () default __.Skipping () = false - default this.CreateMap<'S> (map:'S->'T) (haltingIdx:int) = upcast Map<_,_,_> (map, this, haltingIdx) - default this.CreateFilter (filter:'T->bool) (haltingIdx:int) = upcast Filter (filter, this, haltingIdx) + default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) + default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) - and Choose<'T,'U,'V> (choose:'T->option<'U>, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Choose<'T,'U,'V> (choose:'T->option<'U>, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = match choose input with | Some value -> Helpers.avoidTailCall (next.ProcessNext value) | None -> false - and Distinct<'T,'V when 'T: equality> (next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Distinct<'T,'V when 'T: equality> (next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) @@ -665,8 +686,8 @@ namespace Microsoft.FSharp.Collections else false - and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) @@ -676,8 +697,8 @@ namespace Microsoft.FSharp.Collections else false - and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) @@ -687,10 +708,10 @@ namespace Microsoft.FSharp.Collections else false - and Filter<'T,'V> (filter:'T->bool, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Filter<'T,'V> (filter:'T->bool, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) - override this.CreateMap<'S> (map:'S->'T) (haltingIdx:int) = upcast MapThenFilter<_,_,_> (map, filter, next, haltingIdx) + override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) override __.ProcessNext (input:'T) : bool = if filter input then @@ -698,8 +719,8 @@ namespace Microsoft.FSharp.Collections else false - and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = if filter input then @@ -707,16 +728,16 @@ namespace Microsoft.FSharp.Collections else false - and Map<'T,'U,'V> (map:'T->'U, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Map<'T,'U,'V> (map:'T->'U, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) - override this.CreateFilter (filter:'T->bool) (haltingIdx:int) = upcast FilterThenMap (filter, map, next, haltingIdx) + override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) override __.ProcessNext (input:'T) : bool = Helpers.avoidTailCall (next.ProcessNext (map input)) - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'First,'V>(next, haltingIdx) + and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map @@ -725,18 +746,14 @@ namespace Microsoft.FSharp.Collections if input2.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) else - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx false - interface ISeqComponent with - override __.OnDispose () = - try - input2.Dispose () - finally - (Helpers.upcastISeqComponent next).OnDispose () + override __.OnDispose () = + input2.Dispose () - and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'Second,'V>(next, haltingIdx) + and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + inherit SeqComponent<'Second,'V>(next) let input1 = enumerable1.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map @@ -745,18 +762,14 @@ namespace Microsoft.FSharp.Collections if input1.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) else - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx false - interface ISeqComponent with - override __.OnDispose () = - try - input1.Dispose () - finally - (Helpers.upcastISeqComponent next).OnDispose () + override __.OnDispose () = + input1.Dispose () - and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'First,'V>(next, haltingIdx) + and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () let input3 = enumerable3.GetEnumerator () @@ -766,21 +779,15 @@ namespace Microsoft.FSharp.Collections if input2.MoveNext () && input3.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) else - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx false - interface ISeqComponent with - override __.OnDispose () = - try - input2.Dispose () - finally - try - input3.Dispose () - finally - (Helpers.upcastISeqComponent next).OnDispose () + override __.OnDispose () = + try input2.Dispose () + finally input3.Dispose () - and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = let u = map input @@ -789,8 +796,8 @@ namespace Microsoft.FSharp.Collections else false - and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) let mutable idx = 0 let mapi' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt mapi @@ -799,8 +806,8 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) - and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:ISeqPipeline, next:SeqConsumer<'U,'V>, haltingIdx:int) = - inherit SeqComponent<'First,'V>(next, haltingIdx) + and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + inherit SeqComponent<'First,'V>(next) let mutable idx = 0 let input2 = enumerable2.GetEnumerator () @@ -811,18 +818,14 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) else - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx false - interface ISeqComponent with - override __.OnDispose () = - try - input2.Dispose () - finally - (Helpers.upcastISeqComponent next).OnDispose () + override __.OnDispose () = + input2.Dispose () - and Pairwise<'T,'V> (next:SeqConsumer<'T*'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Pairwise<'T,'V> (next:Consumer<'T*'T,'V>) = + inherit SeqComponent<'T,'V>(next) let mutable isFirst = true let mutable lastValue = Unchecked.defaultof<'T> @@ -837,8 +840,8 @@ namespace Microsoft.FSharp.Collections lastValue <- input Helpers.avoidTailCall (next.ProcessNext currentPair) - and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:SeqConsumer<'State,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:Consumer<'State,'V>) = + inherit SeqComponent<'T,'V>(next) let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let mutable foldResult = initialState @@ -847,8 +850,8 @@ namespace Microsoft.FSharp.Collections foldResult <- f.Invoke(foldResult, input) Helpers.avoidTailCall (next.ProcessNext foldResult) - and Skip<'T,'V> (skipCount:int, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Skip<'T,'V> (skipCount:int, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let mutable count = 0 @@ -866,16 +869,14 @@ namespace Microsoft.FSharp.Collections else Helpers.avoidTailCall (next.ProcessNext input) - interface ISeqComponent with - override __.OnComplete halted = - if count < skipCount then - let x = skipCount - count - invalidOpFmt "tried to skip {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - (Helpers.upcastISeqComponent next).OnComplete halted + override __.OnComplete _ = + if count < skipCount then + let x = skipCount - count + invalidOpFmt "tried to skip {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - and SkipWhile<'T,'V> (predicate:'T->bool, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and SkipWhile<'T,'V> (predicate:'T->bool, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let mutable skip = true @@ -889,29 +890,27 @@ namespace Microsoft.FSharp.Collections else Helpers.avoidTailCall (next.ProcessNext input) - and Take<'T,'V> (takeCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit Truncate<'T, 'V>(takeCount, result, next, haltingIdx) + and Take<'T,'V> (takeCount:int, result:IPipeline, next:Consumer<'T,'V>, pipelineIdx:int) = + inherit Truncate<'T, 'V>(takeCount, result, next, pipelineIdx) - interface ISeqComponent with - override this.OnComplete halted = - if halted = 0 || halted > haltingIdx && this.Count < takeCount then - let x = takeCount - this.Count - invalidOpFmt "tried to take {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - (Helpers.upcastISeqComponent next).OnComplete halted + override this.OnComplete terminatingIdx = + if terminatingIdx < pipelineIdx && this.Count < takeCount then + let x = takeCount - this.Count + invalidOpFmt "tried to take {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - and TakeWhile<'T,'V> (predicate:'T->bool, result:ISeqPipeline, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and TakeWhile<'T,'V> (predicate:'T->bool, result:IPipeline, next:Consumer<'T,'V>, pipeIdx:int) = + inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = if predicate input then Helpers.avoidTailCall (next.ProcessNext input) else - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx false - and Tail<'T, 'V> (next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Tail<'T, 'V> (next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let mutable first = true @@ -922,14 +921,12 @@ namespace Microsoft.FSharp.Collections else Helpers.avoidTailCall (next.ProcessNext input) - interface ISeqComponent with - override this.OnComplete halted = - if first then - invalidArg "source" (SR.GetString(SR.notEnoughElements)) - (Helpers.upcastISeqComponent next).OnComplete halted + override this.OnComplete _ = + if first then + invalidArg "source" (SR.GetString(SR.notEnoughElements)) - and Truncate<'T,'V> (truncateCount:int, result:ISeqPipeline, next:SeqConsumer<'T,'V>, haltingIdx:int) = - inherit SeqComponent<'T,'V>(next, haltingIdx) + and Truncate<'T,'V> (truncateCount:int, result:IPipeline, next:Consumer<'T,'V>, pipeIdx:int) = + inherit SeqComponent<'T,'V>(next) let mutable count = 0 @@ -939,10 +936,10 @@ namespace Microsoft.FSharp.Collections if count < truncateCount then count <- count + 1 if count = truncateCount then - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx next.ProcessNext input else - result.StopFurtherProcessing haltingIdx + result.StopFurtherProcessing pipeIdx false type SeqProcessNextStates = @@ -955,48 +952,48 @@ namespace Microsoft.FSharp.Collections member val Current = Unchecked.defaultof<'T> with get, set member val SeqState = SeqProcessNextStates.NotStarted with get, set - member __.Halted = haltedIdx + member __.HaltedIdx = haltedIdx - interface ISeqPipeline with - member __.StopFurtherProcessing haltingIdx = haltedIdx <- haltingIdx + interface IPipeline with + member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx // SetResult<> is used at the end of the chain of SeqComponents to assign the final value type SetResult<'T> (result:Result<'T>) = - inherit SeqConsumer<'T,'T>() + inherit Consumer<'T,'T>() override __.ProcessNext (input:'T) : bool = result.Current <- input true type Pipeline() = - let mutable halted = 0 - interface ISeqPipeline with member x.StopFurtherProcessing haltingIdx = halted <- haltingIdx - member __.Halted = halted + let mutable haltedIdx = 0 + interface IPipeline with member x.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx + member __.HaltedIdx = haltedIdx module ForEach = - let enumerable (enumerable:IEnumerable<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let enumerable (enumerable:IEnumerable<'T>) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = use enumerator = enumerable.GetEnumerator () - while (pipeline.Halted = 0) && (enumerator.MoveNext ()) do + while (pipeline.HaltedIdx = 0) && (enumerator.MoveNext ()) do consumer.ProcessNext enumerator.Current |> ignore - let array (array:array<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let array (array:array<'T>) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = let mutable idx = 0 - while (pipeline.Halted = 0) && (idx < array.Length) do + while (pipeline.HaltedIdx = 0) && (idx < array.Length) do consumer.ProcessNext array.[idx] |> ignore idx <- idx + 1 - let list (alist:list<'T>) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let list (alist:list<'T>) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = let rec iterate lst = - match pipeline.Halted, lst with + match pipeline.HaltedIdx, lst with | 0, hd :: tl -> consumer.ProcessNext hd |> ignore iterate tl | _ -> () iterate alist - let unfold (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let unfold (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = let rec iterate current = - match pipeline.Halted, generator current with + match pipeline.HaltedIdx, generator current with | 0, Some (item, next) -> consumer.ProcessNext item |> ignore iterate next @@ -1004,16 +1001,16 @@ namespace Microsoft.FSharp.Collections iterate state - let makeIsSkipping (consumer:SeqConsumer<'T,'U>) = + let makeIsSkipping (consumer:Consumer<'T,'U>) = match consumer with | :? SeqComponent<'T,'U> as c -> c.Skipping | _ -> fun () -> false - let init f (terminatingIdx:int) (pipeline:Pipeline) (consumer:SeqConsumer<'T,'U>) = + let init f (terminatingIdx:int) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = let mutable idx = -1 let isSkipping = makeIsSkipping consumer let mutable maybeSkipping = true - while (pipeline.Halted = 0) && (idx < terminatingIdx) do + while (pipeline.HaltedIdx = 0) && (idx < terminatingIdx) do if maybeSkipping then maybeSkipping <- isSkipping () @@ -1022,13 +1019,13 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 - let execute (f:ISeqPipeline->#SeqConsumer<'U,'U>) (current:SeqComponentFactory<'T,'U>) executeOn = + let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:SeqComponentFactory<'T,'U>) executeOn = let pipeline = Pipeline() - let result = f pipeline - let consumer = current.Create pipeline result 1 + let result = f (fun () -> (pipeline:>IPipeline).StopFurtherProcessing (current.PipeIdx+1)) + let consumer = current.Create pipeline emptyPipeIdx result try executeOn pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete pipeline.Halted + (Helpers.upcastISeqComponent consumer).OnComplete pipeline.HaltedIdx result finally (Helpers.upcastISeqComponent consumer).OnDispose () @@ -1050,7 +1047,7 @@ namespace Microsoft.FSharp.Collections static member Element = element [] - type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ISeqComponent) = + type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ICompletionChaining) = interface IDisposable with member __.Dispose() : unit = seqComponent.OnDispose () @@ -1087,18 +1084,18 @@ namespace Microsoft.FSharp.Collections member this.GetEnumerator () : IEnumerator<'T> = failwith "library implementation error: derived class should implement (should be abstract)" - and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = + and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = inherit EnumeratorBase<'U>(result, seqComponent) let rec moveNext () = - if (result.Halted = 0) && source.MoveNext () then + if (result.HaltedIdx = 0) && source.MoveNext () then if seqComponent.ProcessNext source.Current then true else moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete result.Halted + (Helpers.upcastISeqComponent seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1119,12 +1116,12 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result (SetResult<'U> result) 1, result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.enumerable enumerable) and ConcatEnumerator<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = @@ -1178,7 +1175,7 @@ namespace Microsoft.FSharp.Collections override this.Append source = Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = + override this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable this) and ConcatEnumerable<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = @@ -1191,14 +1188,14 @@ namespace Microsoft.FSharp.Collections override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = Helpers.upcastEnumerable (Enumerable<'T,'V>(this, next)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = + override this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable this) let create enumerable current = Helpers.upcastEnumerable (Enumerable(enumerable, current)) module Array = - type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = + type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let mutable idx = 0 @@ -1213,7 +1210,7 @@ namespace Microsoft.FSharp.Collections initMoveNext <- ignore let rec moveNext () = - if (result.Halted = 0) && idx < array.Length then + if (result.HaltedIdx = 0) && idx < array.Length then idx <- idx+1 if seqComponent.ProcessNext array.[idx-1] then true @@ -1221,7 +1218,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete result.Halted + (Helpers.upcastISeqComponent seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1235,12 +1232,12 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result (SetResult<'U> result) 1, result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.array (delayedArray ())) let createDelayed (delayedArray:unit->array<'T>) (current:SeqComponentFactory<'T,'U>) = @@ -1256,13 +1253,13 @@ namespace Microsoft.FSharp.Collections create array IdentityFactory.IdentityFactory module List = - type Enumerator<'T,'U>(alist:list<'T>, seqComponent:SeqConsumer<'T,'U>, result:Result<'U>) = + type Enumerator<'T,'U>(alist:list<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let mutable list = alist let rec moveNext current = - match result.Halted, current with + match result.HaltedIdx, current with | 0, head::tail -> if seqComponent.ProcessNext head then list <- tail @@ -1271,7 +1268,7 @@ namespace Microsoft.FSharp.Collections moveNext tail | _ -> result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete result.Halted + (Helpers.upcastISeqComponent seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1285,25 +1282,25 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result (SetResult<'U> result) 1, result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.list alist) let create alist current = Helpers.upcastEnumerable (Enumerable(alist, current)) module Unfold = - type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:SeqConsumer<'T,'U>, signal:Result<'U>) = + type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, signal:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) let mutable current = state let rec moveNext () = - match signal.Halted, generator current with + match signal.HaltedIdx, generator current with | 0, Some (item, nextState) -> current <- nextState if seqComponent.ProcessNext item then @@ -1323,12 +1320,12 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result (SetResult<'U> result) 1, result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'U,'U>) = + override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.unfold generator state) module Init = @@ -1351,7 +1348,7 @@ namespace Microsoft.FSharp.Collections else System.Int32.MaxValue - type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:SeqConsumer<'T,'U>, signal:Result<'U>) = + type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:Consumer<'T,'U>, signal:Result<'U>) = inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) let isSkipping = @@ -1364,7 +1361,7 @@ namespace Microsoft.FSharp.Collections let mutable idx = -1 let rec moveNext () = - if (signal.Halted = 0) && idx < terminatingIdx then + if (signal.HaltedIdx = 0) && idx < terminatingIdx then idx <- idx + 1 if maybeSkipping then @@ -1378,11 +1375,11 @@ namespace Microsoft.FSharp.Collections true else moveNext () - elif (signal.Halted = 0) && idx = System.Int32.MaxValue then + elif (signal.HaltedIdx = 0) && idx = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) else signal.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete signal.Halted + (Helpers.upcastISeqComponent seqComponent).OnComplete signal.HaltedIdx false interface IEnumerator with @@ -1396,12 +1393,12 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result (SetResult<'U> result) 1, result)) + Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) - override this.ForEach (createResult:ISeqPipeline->#SeqConsumer<'U,'U>) = + override this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = let terminatingIdx = getTerminatingIdx count ForEach.execute createResult current (ForEach.init f terminatingIdx) @@ -1468,7 +1465,7 @@ namespace Microsoft.FSharp.Collections override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) - override this.ForEach (f:ISeqPipeline->#SeqConsumer<'T,'T>) = + override this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable (Helpers.upcastEnumerable this)) #if FX_NO_ICLONEABLE @@ -1479,13 +1476,13 @@ namespace Microsoft.FSharp.Collections let inline indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) [] - let toComposer (source:seq<'T>): SeqComposer.SeqEnumerable<'T> = + let toComposer (source:seq<'T>): Composer.Internal.SeqEnumerable<'T> = checkNonNull "source" source match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> upcast s - | :? array<'T> as a -> upcast SeqComposer.Array.Enumerable((fun () -> a), SeqComposer.IdentityFactory.IdentityFactory) - | :? list<'T> as a -> upcast SeqComposer.List.Enumerable(a, SeqComposer.IdentityFactory.IdentityFactory) - | _ -> upcast SeqComposer.Enumerable.Enumerable<'T,'T>(source, SeqComposer.IdentityFactory.IdentityFactory) + | :? Composer.Enumerable.EnumerableBase<'T> as s -> upcast s + | :? array<'T> as a -> upcast Composer.Array.Enumerable((fun () -> a), Composer.IdentityFactory.IdentityFactory) + | :? list<'T> as a -> upcast Composer.List.Enumerable(a, Composer.IdentityFactory.IdentityFactory) + | _ -> upcast Composer.Enumerable.Enumerable<'T,'T>(source, Composer.IdentityFactory.IdentityFactory) let inline foreach f (source:seq<_>) = source @@ -1508,26 +1505,26 @@ namespace Microsoft.FSharp.Collections [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> = - SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Unfold.Enumerable<'T,'T,'State>(generator, state, SeqComposer.IdentityFactory.IdentityFactory)) + Composer.Helpers.upcastEnumerable (new Composer.Unfold.Enumerable<'T,'T,'State>(generator, state, Composer.IdentityFactory.IdentityFactory)) [] let empty<'T> = (EmptyEnumerable :> seq<'T>) [] let initInfinite<'T> (f:int->'T) : IEnumerable<'T> = - SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Init.EnumerableDecider<'T>(Nullable (), f)) + Composer.Helpers.upcastEnumerable (new Composer.Init.EnumerableDecider<'T>(Nullable (), f)) [] let init<'T> (count:int) (f:int->'T) : IEnumerable<'T> = if count < 0 then invalidArgInputMustBeNonNegative "count" count elif count = 0 then empty else - SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Init.EnumerableDecider<'T>(Nullable count, f)) + Composer.Helpers.upcastEnumerable (new Composer.Init.EnumerableDecider<'T>(Nullable count, f)) [] let iter f (source : seq<'T>) = source |> foreach (fun _ -> - { new SeqComposer.SeqConsumer<'T,'T> () with + { new Composer.Internal.Consumer<'T,'T> () with override this.ProcessNext value = f value Unchecked.defaultof }) @@ -1557,12 +1554,12 @@ namespace Microsoft.FSharp.Collections let tryItem i (source : seq<'T>) = if i < 0 then None else source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, SeqComposer.Values>> (SeqComposer.Values<_, _> (0, None)) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Composer.Internal.Values>> (Composer.Internal.Values<_, _> (0, None)) with override this.ProcessNext value = if this.Value._1 = i then this.Value._2 <- Some value - pipeline.StopFurtherProcessing 1 + halt () else this.Value._1 <- this.Value._1 + 1 Unchecked.defaultof }) @@ -1576,7 +1573,7 @@ namespace Microsoft.FSharp.Collections let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) source |> foreach (fun _ -> - { new SeqComposer.Folder<'T, int> (0) with + { new Composer.Internal.Folder<'T, int> (0) with override this.ProcessNext value = f.Invoke(this.Value, value) this.Value <- this.Value + 1 @@ -1586,12 +1583,12 @@ namespace Microsoft.FSharp.Collections [] let exists f (source : seq<'T>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, bool> (false) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, bool> (false) with override this.ProcessNext value = if f value then this.Value <- true - pipeline.StopFurtherProcessing 1 + halt () Unchecked.defaultof }) |> fun exists -> exists.Value @@ -1599,12 +1596,12 @@ namespace Microsoft.FSharp.Collections [] let inline contains element (source : seq<'T>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, bool> (false) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, bool> (false) with override this.ProcessNext value = if element = value then this.Value <- true - pipeline.StopFurtherProcessing 1 + halt () Unchecked.defaultof }) |> fun contains -> contains.Value @@ -1612,12 +1609,12 @@ namespace Microsoft.FSharp.Collections [] let forall f (source : seq<'T>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, bool> (true) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, bool> (true) with override this.ProcessNext value = if not (f value) then this.Value <- false - pipeline.StopFurtherProcessing 1 + halt () Unchecked.defaultof }) |> fun forall -> forall.Value @@ -1669,57 +1666,51 @@ namespace Microsoft.FSharp.Collections let private seqFactory createSeqComponent (source:seq<'T>) = checkNonNull "source" source match source with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Compose createSeqComponent - | :? array<'T> as a -> SeqComposer.Array.create a createSeqComponent - | :? list<'T> as a -> SeqComposer.List.create a createSeqComponent - | _ -> SeqComposer.Enumerable.create source createSeqComponent + | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Compose createSeqComponent + | :? array<'T> as a -> Composer.Array.create a createSeqComponent + | :? list<'T> as a -> Composer.List.create a createSeqComponent + | _ -> Composer.Enumerable.create source createSeqComponent [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = - Composer.Seq.filter f (toComposer source) - |> Upcast.enumerable + source |> seqFactory (Composer.FilterFactory f) [] let where f source = filter f source [] let map<'T,'U> (f:'T->'U) (source:seq<'T>) : seq<'U> = - Composer.Seq.map f (toComposer source) - |> Upcast.enumerable + source |> seqFactory (Composer.MapFactory f) [] - let mapi f source = - let f' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f - Composer.Seq.mapi_adapt f' (toComposer source) - |> Upcast.enumerable + let mapi f source = + source |> seqFactory (Composer.MapiFactory f) [] let mapi2 f source1 source2 = checkNonNull "source2" source2 - source1 |> seqFactory (SeqComposer.Mapi2Factory (f, source2)) + source1 |> seqFactory (Composer.Mapi2Factory (f, source2)) [] let map2<'T,'U,'V> (f:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = checkNonNull "source1" source1 match source1 with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Compose (SeqComposer.Map2FirstFactory (f, source2)) - | _ -> source2 |> seqFactory (SeqComposer.Map2SecondFactory (f, source1)) + | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Compose (Composer.Map2FirstFactory (f, source2)) + | _ -> source2 |> seqFactory (Composer.Map2SecondFactory (f, source1)) [] let map3 f source1 source2 source3 = checkNonNull "source2" source2 checkNonNull "source3" source3 - source1 |> seqFactory (SeqComposer.Map3Factory (f, source2, source3)) + source1 |> seqFactory (Composer.Map3Factory (f, source2, source3)) [] - let choose f source = - Composer.Seq.choose f (toComposer source) - |> Upcast.enumerable + let choose f source = + source |> seqFactory (Composer.ChooseFactory f) [] let indexed source = - Composer.Seq.indexed (toComposer source) - |> Upcast.enumerable + source |> seqFactory (Composer.MapiFactory (fun i x -> i,x) ) [] let zip source1 source2 = @@ -1737,13 +1728,13 @@ namespace Microsoft.FSharp.Collections [] let tryPick f (source : seq<'T>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, Option<'U>> (None) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Option<'U>> (None) with override this.ProcessNext value = match f value with | (Some _) as some -> this.Value <- some - pipeline.StopFurtherProcessing 1 + halt () | None -> () Unchecked.defaultof }) |> fun pick -> pick.Value @@ -1757,12 +1748,12 @@ namespace Microsoft.FSharp.Collections [] let tryFind f (source : seq<'T>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, Option<'T>> (None) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Option<'T>> (None) with override this.ProcessNext value = if f value then this.Value <- Some value - pipeline.StopFurtherProcessing 1 + halt () Unchecked.defaultof }) |> fun find -> find.Value @@ -1777,7 +1768,7 @@ namespace Microsoft.FSharp.Collections if count < 0 then invalidArgInputMustBeNonNegative "count" count (* Note: don't create or dispose any IEnumerable if n = 0 *) if count = 0 then empty else - source |> seqFactory (Composer.Seq.TakeFactory count) + source |> seqFactory (Composer.TakeFactory count) [] let isEmpty (source : seq<'T>) = @@ -1793,7 +1784,7 @@ namespace Microsoft.FSharp.Collections [] let concat (sources:seq<#seq<'T>>) : seq<'T> = checkNonNull "sources" sources - upcast SeqComposer.Enumerable.ConcatEnumerable sources + upcast Composer.Enumerable.ConcatEnumerable sources [] let length (source : seq<'T>) = @@ -1815,7 +1806,7 @@ namespace Microsoft.FSharp.Collections source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,'State> (x) with + { new Composer.Internal.Folder<'T,'State> (x) with override this.ProcessNext value = this.Value <- f.Invoke (this.Value, value) Unchecked.defaultof }) @@ -1853,7 +1844,7 @@ namespace Microsoft.FSharp.Collections source |> foreach (fun _ -> - { new SeqComposer.Folder<'T, SeqComposer.Values> (SeqComposer.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -1862,9 +1853,8 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- f.Invoke (this.Value._2, value) Unchecked.defaultof - interface SeqComposer.ISeqComponent with member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'T, SeqComposer.Values>).Value._1 then + if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun reduced -> reduced.Value._2 @@ -1878,8 +1868,8 @@ namespace Microsoft.FSharp.Collections checkNonNull "source1" source1 checkNonNull "source2" source2 match source1 with - | :? SeqComposer.Enumerable.EnumerableBase<'T> as s -> s.Append source2 - | _ -> SeqComposer.Helpers.upcastEnumerable (new SeqComposer.Enumerable.AppendEnumerable<_>([source2; source1])) + | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Append source2 + | _ -> Composer.Helpers.upcastEnumerable (new Composer.Enumerable.AppendEnumerable<_>([source2; source1])) [] @@ -1923,7 +1913,7 @@ namespace Microsoft.FSharp.Collections [] let ofArray (source : 'T array) = checkNonNull "source" source - SeqComposer.Array.createId source + Composer.Array.createId source [] let toArray (source : seq<'T>) = @@ -1977,17 +1967,17 @@ namespace Microsoft.FSharp.Collections [] let truncate n (source: seq<'T>) = if n <= 0 then empty else - source |> seqFactory (Composer.Seq.TruncateFactory n) + source |> seqFactory (Composer.TruncateFactory n) [] let pairwise<'T> (source:seq<'T>) : seq<'T*'T> = - source |> seqFactory (Composer.Seq.PairwiseFactory ()) + source |> seqFactory (Composer.PairwiseFactory ()) [] let scan<'T,'State> f (z:'State) (source : seq<'T>): seq<'State> = let first = [|z|] :> IEnumerable<'State> - let rest = source |> seqFactory (SeqComposer.ScanFactory (f, z)) - upcast SeqComposer.Enumerable.ConcatEnumerable [|first; rest;|] + let rest = source |> seqFactory (Composer.ScanFactory (f, z)) + upcast Composer.Enumerable.ConcatEnumerable [|first; rest;|] [] let tryFindBack f (source : seq<'T>) = @@ -2010,12 +2000,12 @@ namespace Microsoft.FSharp.Collections [] let tryFindIndex p (source:seq<_>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, SeqComposer.Values, int>> (SeqComposer.Values<_,_>(None, 0)) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Composer.Internal.Values, int>> (Composer.Internal.Values<_,_>(None, 0)) with override this.ProcessNext value = if p value then this.Value._1 <- Some(this.Value._2) - pipeline.StopFurtherProcessing 1 + halt () else this.Value._2 <- this.Value._2 + 1 Unchecked.defaultof @@ -2161,11 +2151,11 @@ namespace Microsoft.FSharp.Collections [] let distinct source = - source |> seqFactory (Composer.Seq.DistinctFactory ()) + source |> seqFactory (Composer.DistinctFactory ()) [] let distinctBy keyf source = - source |> seqFactory (Composer.Seq.DistinctByFactory keyf) + source |> seqFactory (Composer.DistinctByFactory keyf) [] let sortBy keyf source = @@ -2174,7 +2164,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceBy keyf array array - SeqComposer.Array.createDelayedId delayedSort + Composer.Array.createDelayedId delayedSort [] let sort source = @@ -2183,7 +2173,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlace array array - SeqComposer.Array.createDelayedId delayedSort + Composer.Array.createDelayedId delayedSort [] let sortWith f source = @@ -2192,7 +2182,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceWith f array array - SeqComposer.Array.createDelayedId delayedSort + Composer.Array.createDelayedId delayedSort [] let inline sortByDescending keyf source = @@ -2243,7 +2233,7 @@ namespace Microsoft.FSharp.Collections let inline sum (source:seq<'a>) : 'a = source |> foreach (fun _ -> - { new SeqComposer.Folder<'a,'a> (LanguagePrimitives.GenericZero) with + { new Composer.Internal.Folder<'a,'a> (LanguagePrimitives.GenericZero) with override this.ProcessNext value = this.Value <- Checked.(+) this.Value value Unchecked.defaultof }) @@ -2253,7 +2243,7 @@ namespace Microsoft.FSharp.Collections let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + { new Composer.Internal.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with override this.ProcessNext value = this.Value <- Checked.(+) this.Value (f value) Unchecked.defaultof }) @@ -2263,15 +2253,14 @@ namespace Microsoft.FSharp.Collections let inline average (source: seq< ^a>) : ^a = source |> foreach (fun _ -> - { new SeqComposer.Folder<'a, SeqComposer.Values<'a, int>> (SeqComposer.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + { new Composer.Internal.Folder<'a, Composer.Internal.Values<'a, int>> (Composer.Internal.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 value this.Value._2 <- this.Value._2 + 1 Unchecked.defaultof - interface SeqComposer.ISeqComponent with member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'a, SeqComposer.Values<'a, int>>).Value._2 = 0 then + if this.Value._2 = 0 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun total -> LanguagePrimitives.DivideByInt< ^a> total.Value._1 total.Value._2 @@ -2279,14 +2268,14 @@ namespace Microsoft.FSharp.Collections let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,SeqComposer.Values<'U, int>> (SeqComposer.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + { new Composer.Internal.Folder<'T,Composer.Internal.Values<'U, int>> (Composer.Internal.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 (f value) this.Value._2 <- this.Value._2 + 1 Unchecked.defaultof - interface SeqComposer.ISeqComponent with + member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'T,SeqComposer.Values<'U, int>>).Value._2 = 0 then + if this.Value._2 = 0 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun total -> LanguagePrimitives.DivideByInt< ^U> total.Value._1 total.Value._2 @@ -2299,7 +2288,7 @@ namespace Microsoft.FSharp.Collections let inline min (source: seq<_>) = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2308,9 +2297,8 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- value Unchecked.defaultof - interface SeqComposer.ISeqComponent with member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun min -> min.Value._2 @@ -2319,7 +2307,7 @@ namespace Microsoft.FSharp.Collections let inline minBy (f : 'T -> 'U) (source: seq<'T>) : 'T = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with override this.ProcessNext value = match this.Value._1, f value with | true, valueU -> @@ -2332,9 +2320,8 @@ namespace Microsoft.FSharp.Collections | _ -> () Unchecked.defaultof - interface SeqComposer.ISeqComponent with member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun min -> min.Value._3 @@ -2359,7 +2346,7 @@ namespace Microsoft.FSharp.Collections let inline max (source: seq<_>) = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2368,9 +2355,8 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- value Unchecked.defaultof - interface SeqComposer.ISeqComponent with member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun max -> max.Value._2 @@ -2379,7 +2365,7 @@ namespace Microsoft.FSharp.Collections let inline maxBy (f : 'T -> 'U) (source: seq<'T>) : 'T = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T,SeqComposer.Values> (SeqComposer.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with override this.ProcessNext value = match this.Value._1, f value with | true, valueU -> @@ -2392,9 +2378,8 @@ namespace Microsoft.FSharp.Collections | _ -> () Unchecked.defaultof - interface SeqComposer.ISeqComponent with member this.OnComplete _ = - if (this:?>SeqComposer.Folder<'T,SeqComposer.Values>).Value._1 then + if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun min -> min.Value._3 @@ -2418,11 +2403,15 @@ namespace Microsoft.FSharp.Collections *) [] let takeWhile p (source: seq<_>) = - source |> seqFactory (Composer.Seq.TakeWhileFactory p) + source |> seqFactory (Composer.TakeWhileFactory p) + + [] + let skip count (source: seq<_>) = + source |> seqFactory (Composer.SkipFactory count) [] let skipWhile p (source: seq<_>) = - source |> seqFactory (Composer.Seq.SkipWhileFactory p) + source |> seqFactory (Composer.SkipWhileFactory p) [] let forall2 p (source1: seq<_>) (source2: seq<_>) = @@ -2441,11 +2430,11 @@ namespace Microsoft.FSharp.Collections [] let tryHead (source : seq<_>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, Option<'T>> (None) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Option<'T>> (None) with override this.ProcessNext value = this.Value <- Some value - pipeline.StopFurtherProcessing 1 + halt () Unchecked.defaultof }) |> fun head -> head.Value @@ -2470,13 +2459,13 @@ namespace Microsoft.FSharp.Collections [] let tail (source: seq<'T>) = - source |> seqFactory (SeqComposer.TailFactory ()) + source |> seqFactory (Composer.TailFactory ()) [] let tryLast (source : seq<_>) = source |> foreach (fun _ -> - { new SeqComposer.Folder<'T, SeqComposer.Values> (SeqComposer.Values(true, Unchecked.defaultof<'T>)) with + { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2497,24 +2486,22 @@ namespace Microsoft.FSharp.Collections [] let exactlyOne (source : seq<_>) = source - |> foreach (fun pipeline -> - { new SeqComposer.Folder<'T, SeqComposer.Values> (SeqComposer.Values(true, Unchecked.defaultof<'T>, false)) with + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values(true, Unchecked.defaultof<'T>, false)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false this.Value._2 <- value else this.Value._3 <- true - pipeline.StopFurtherProcessing 1 + halt () Unchecked.defaultof - interface SeqComposer.ISeqComponent with + member this.OnComplete _ = - let value = (this:?>SeqComposer.Folder<'T,SeqComposer.Values>) - if value.Value._1 then + if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - elif value.Value._3 then - invalidArg "source" (SR.GetString(SR.inputSequenceTooLong)) - }) + elif this.Value._3 then + invalidArg "source" (SR.GetString(SR.inputSequenceTooLong)) }) |> fun one -> one.Value._2 member this.OnComplete _ = @@ -2531,7 +2518,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.Reverse array array - SeqComposer.Array.createDelayedId delayedReverse + Composer.Array.createDelayedId delayedReverse [] let permute f (source:seq<_>) = @@ -2540,7 +2527,7 @@ namespace Microsoft.FSharp.Collections source |> toArray |> Array.permute f - SeqComposer.Array.createDelayedId delayedPermute + Composer.Array.createDelayedId delayedPermute [] let mapFold<'T,'State,'Result> (f: 'State -> 'T -> 'Result * 'State) acc source = @@ -2558,7 +2545,7 @@ namespace Microsoft.FSharp.Collections [] let except (itemsToExclude: seq<'T>) (source: seq<'T>) = checkNonNull "itemsToExclude" itemsToExclude - source |> seqFactory (Composer.Seq.ExceptFactory itemsToExclude) + source |> seqFactory (Composer.ExceptFactory itemsToExclude) [] let chunkBySize chunkSize (source : seq<_>) = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index b3fdc5639da..b554294d6d8 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -13,48 +13,66 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = - module SeqComposer = - type ISeqComponent = - abstract OnComplete : int -> unit - abstract OnDispose : unit -> unit - - type ISeqPipeline = - abstract StopFurtherProcessing : int -> unit - - [] - type SeqConsumer<'T,'U> = - new : unit -> SeqConsumer<'T,'U> - abstract ProcessNext : input:'T -> bool - interface ISeqComponent - - [] - type Values<'a,'b> = - struct - new : a:'a * b:'b -> Values<'a,'b> - val mutable _1: 'a - val mutable _2: 'b - end - - [] - type Values<'a,'b,'c> = - struct - new : a:'a * b:'b * c:'c -> Values<'a,'b,'c> - val mutable _1: 'a - val mutable _2: 'b - val mutable _3: 'c - end - - [] - type Folder<'T,'U> = - class - inherit SeqConsumer<'T,'T> - new : init:'U -> Folder<'T,'U> - val mutable Value: 'U - end - - [] - type SeqEnumerable<'T> = - abstract member ForEach<'a when 'a :> SeqConsumer<'T,'T>> : f:(ISeqPipeline->'a) -> 'a + module Composer = + module Internal = + /// PipeIdx denotes the index of the element within the pipeline. 0 denotes the + /// source of the chain. + type PipeIdx = int + + /// ICompletionChaining is used to correctly handle cleaning up of the pipeline. A + /// base implementation is provided in Consumer, and should not be overwritten. Consumer + /// provides it's own OnComplete and OnDispose function which should be used to handle + /// a particular consumers cleanup. + type ICompletionChaining = + /// OnComplete is used to determine if the object has been processed correctly, + /// and possibly throw exceptions to denote incorrect application (i.e. such as a Take + /// operation which didn't have a source at least as large as was required). It is + /// not called in the case of an exception being thrown whilst the stream is still + /// being processed. + abstract OnComplete : PipeIdx -> unit + /// OnDispose is used to cleanup the stream. It is always called at the last operation + /// after the enumeration has completed. + abstract OnDispose : unit -> unit + + /// Consumer is the base class of all elements within the pipeline + [] + type Consumer<'T,'U> = + interface ICompletionChaining + new : unit -> Consumer<'T,'U> + abstract member ProcessNext : input:'T -> bool + abstract member OnComplete : PipeIdx -> unit + abstract member OnDispose : unit -> unit + + /// Values is a mutable struct. It can be embedded within the folder type + /// if two values are required for the calculation. + [] + type Values<'a,'b> = + new : a:'a * b:'b -> Values<'a,'b> + val mutable _1: 'a + val mutable _2: 'b + + /// Values is a mutable struct. It can be embedded within the folder type + /// if three values are required for the calculation. + [] + type Values<'a,'b,'c> = + new : a:'a * b:'b * c:'c -> Values<'a,'b,'c> + val mutable _1: 'a + val mutable _2: 'b + val mutable _3: 'c + + /// Folder is a base class to assist with fold-like operations. It's intended usage + /// is as a base class for an object expression that will be used from within + /// the ForEach function. + [] + type Folder<'T,'U> = + inherit Consumer<'T,'T> + new : init:'U -> Folder<'T,'U> + val mutable Value: 'U + + /// SeqEnumerable functions provide the enhance seq experience + [] + type SeqEnumerable<'T> = + abstract member ForEach<'a when 'a :> Consumer<'T,'T>> : f:((unit->unit)->'a) -> 'a /// Returns a new sequence that contains the cartesian product of the two input sequences. /// The first sequence. @@ -1247,7 +1265,7 @@ namespace Microsoft.FSharp.Collections /// /// Thrown when the input sequence is null. [] - val toComposer : source:seq<'T> -> SeqComposer.SeqEnumerable<'T> + val toComposer : source:seq<'T> -> Composer.Internal.SeqEnumerable<'T> /// Builds a list from the given collection. /// From b2cda991b98850657cadf3e94dd4e53d7589ecfd Mon Sep 17 00:00:00 2001 From: liboz Date: Wed, 26 Oct 2016 22:09:06 -0400 Subject: [PATCH 45/59] seq.comparewith --- src/fsharp/FSharp.Core/seq.fs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 3dfb9f9f3de..86b76fa7e0c 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -1881,24 +1881,34 @@ namespace Microsoft.FSharp.Collections use e2 = source2.GetEnumerator() let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) + let mutable e2ok = Unchecked.defaultof source1 |> foreach (fun halt -> - { new Composer.Core.Folder<'T,int> (0) with + { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values<_,_>(false, 0)) with override this.ProcessNext value = - if not (e2.MoveNext()) then - this.Value <- 1 + e2ok <- e2.MoveNext() + if not e2ok then + this.Value._1 <- true + this.Value._2 <- 1 halt () else - let c = f.Invoke (value, e2.Current) + let c = f.Invoke(value, e2.Current) if c <> 0 then - this.Value <- c + this.Value._1 <- true + this.Value._2 <- c halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + Unchecked.defaultof member this.OnComplete _ = - if this.Value = 0 && e2.MoveNext() then - this.Value <- -1 }) - |> fun compare -> compare.Value + if not this.Value._1 then + e2ok <- e2.MoveNext() + if e2ok then + this.Value._2 <- -1 + else + this.Value._2 <- 0 + + }) + |> fun compare -> compare.Value._2 [] let ofList (source : 'T list) = From f1ac6bd6f338b5f5158f0067620d95e937c2c0a4 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 27 Oct 2016 08:49:21 +0200 Subject: [PATCH 46/59] More compact Seq.compareWith Bit faster on 64 bit, as don't need to access the ref of e2ok oops, type-o ! Minimalist exposure of factory infrastructire - made SeqEnumerable<> into an interface (ISeq<>) - made SeqComponentFactory<> into an interface (ISeqFactory<>) Renaming recommentations base on @rmunn feedback Commented strange Unchecked.default usage Partial move to Composer module In the Composer module we use ISeq rather than seq. An end goal could be be publicly expose this module for enhanced performancy. --- src/fsharp/FSharp.Core/seq.fs | 711 ++++++++++++++++++++------------- src/fsharp/FSharp.Core/seq.fsi | 18 +- 2 files changed, 438 insertions(+), 291 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 86b76fa7e0c..ea249208d6d 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -467,7 +467,7 @@ namespace Microsoft.FSharp.Collections abstract OnComplete : PipeIdx -> unit abstract OnDispose : unit -> unit - type IPipeline = + type IOutOfBand = abstract StopFurtherProcessing : PipeIdx -> unit [] @@ -521,9 +521,14 @@ namespace Microsoft.FSharp.Collections Value = init } - [] - type SeqEnumerable<'T>() = - abstract member ForEach<'a when 'a :> Consumer<'T,'T>> : f:((unit->unit)->'a) -> 'a + type ISeqFactory<'T,'U> = + abstract PipeIdx : PipeIdx + abstract Create<'V> : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> + + type ISeq<'T> = + inherit IEnumerable<'T> + abstract member Compose<'U> : (ISeqFactory<'T,'U>) -> ISeq<'U> + abstract member ForEach<'consumer when 'consumer :> Consumer<'T,'T>> : f:((unit->unit)->'consumer) -> 'consumer open Internal @@ -535,114 +540,137 @@ namespace Microsoft.FSharp.Collections // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality // is fixed with the compiler then these functions can be removed. + let inline upcastSeq (t:#ISeq<'T>) : ISeq<'T> = (# "" t : ISeq<'T> #) + let inline upcastFactory (t:#ISeqFactory<'T,'U>) : ISeqFactory<'T,'U> = (# "" t : ISeqFactory<'T,'U> #) let inline upcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) - let inline upcastISeqComponent (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) + let inline upcastICompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) type [] SeqComponentFactory<'T,'U> (pipeIdx:``PipeIdx?``) = - abstract Create<'V> : IPipeline -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> - new() = SeqComponentFactory<'T,'U> (emptyPipeIdx) - member __.PipeIdx = getPipeIdx pipeIdx + interface ISeqFactory<'T,'U> with + member __.PipeIdx = getPipeIdx pipeIdx + member __.Create _ _ _ = failwith "library implementation error: Create on base factory should not be called" - and ComposedFactory<'T,'U,'V> private (first:SeqComponentFactory<'T,'U>, second:SeqComponentFactory<'U,'V>, secondPipeIdx:PipeIdx) = + and ComposedFactory<'T,'U,'V> private (first:ISeqFactory<'T,'U>, second:ISeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = inherit SeqComponentFactory<'T,'V> (makePipeIdx secondPipeIdx) - override this.Create<'W> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'V,'W>) : Consumer<'T,'W> = - first.Create result pipeIdx (second.Create result (makePipeIdx secondPipeIdx) next) + interface ISeqFactory<'T,'V> with + member this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'V,'W>) : Consumer<'T,'W> = + first.Create outOfBand pipeIdx (second.Create outOfBand (makePipeIdx secondPipeIdx) next) - static member Combine (first:SeqComponentFactory<'T,'U>) (second:SeqComponentFactory<'U,'V>) : SeqComponentFactory<'T,'V> = - upcast ComposedFactory(first, second, first.PipeIdx+1) + static member Combine (first:ISeqFactory<'T,'U>) (second:ISeqFactory<'U,'V>) : ISeqFactory<'T,'V> = + ComposedFactory(first, second, first.PipeIdx+1) |> Helpers.upcastFactory and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) + interface ISeqFactory<'T,'U> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) and DistinctFactory<'T when 'T: equality> () = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) and FilterFactory<'T> (filter:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = - match next with - | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter - | _ -> upcast Filter (filter, next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = + match next with + | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter + | _ -> upcast Filter (filter, next) and IdentityFactory<'T> () = inherit SeqComponentFactory<'T,'T> () static let singleton = IdentityFactory<'T>() - override __.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next - static member IdentityFactory = singleton + interface ISeqFactory<'T,'T> with + member __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next + static member Instance = singleton and MapFactory<'T,'U> (map:'T->'U) = inherit SeqComponentFactory<'T,'U> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = - match next with - | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map - | _ -> upcast Map<_,_,_> (map, next) + interface ISeqFactory<'T,'U> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = + match next with + | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map + | _ -> upcast Map<_,_,_> (map, next) and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'First,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, outOfBand, next, getPipeIdx pipeIdx) and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = inherit SeqComponentFactory<'Second,'U> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'Second,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, outOfBand, next, getPipeIdx pipeIdx) and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = inherit SeqComponentFactory<'First,'U> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'First,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, outOfBand, next, getPipeIdx pipeIdx) and MapiFactory<'T,'U> (mapi:int->'T->'U) = inherit SeqComponentFactory<'T,'U> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Mapi (mapi, next) + interface ISeqFactory<'T,'U> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Mapi (mapi, next) and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = inherit SeqComponentFactory<'First,'U> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'First,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, outOfBand, next, getPipeIdx pipeIdx) and PairwiseFactory<'T> () = inherit SeqComponentFactory<'T,'T*'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) + interface ISeqFactory<'T,'T*'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) and ScanFactory<'T,'State> (folder:'State->'T->'State, initialState:'State) = inherit SeqComponentFactory<'T,'State> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) + interface ISeqFactory<'T,'State> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) and SkipFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, next) and SkipWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) and TakeWhileFactory<'T> (predicate:'T->bool) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, outOfBand, next, getPipeIdx pipeIdx) and TakeFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, outOfBand, next, getPipeIdx pipeIdx) and TailFactory<'T> () = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (_result:IPipeline) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) and TruncateFactory<'T> (count:int) = inherit SeqComponentFactory<'T,'T> () - override this.Create<'V> (result:IPipeline) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, result, next, getPipeIdx pipeIdx) + interface ISeqFactory<'T,'T> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, getPipeIdx pipeIdx) and [] SeqComponent<'T,'U> (next:ICompletionChaining) = inherit Consumer<'T,'U>() @@ -736,7 +764,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = Helpers.avoidTailCall (next.ProcessNext (map input)) - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () @@ -746,13 +774,13 @@ namespace Microsoft.FSharp.Collections if input2.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) else - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx false override __.OnDispose () = input2.Dispose () - and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = inherit SeqComponent<'Second,'V>(next) let input1 = enumerable1.GetEnumerator () @@ -762,13 +790,13 @@ namespace Microsoft.FSharp.Collections if input1.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) else - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx false override __.OnDispose () = input1.Dispose () - and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () @@ -779,7 +807,7 @@ namespace Microsoft.FSharp.Collections if input2.MoveNext () && input3.MoveNext () then Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) else - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx false override __.OnDispose () = @@ -806,7 +834,7 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) - and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, result:IPipeline, next:Consumer<'U,'V>, pipeIdx:int) = + and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = inherit SeqComponent<'First,'V>(next) let mutable idx = 0 @@ -818,7 +846,7 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 Helpers.avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) else - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx false override __.OnDispose () = @@ -890,8 +918,8 @@ namespace Microsoft.FSharp.Collections else Helpers.avoidTailCall (next.ProcessNext input) - and Take<'T,'V> (takeCount:int, result:IPipeline, next:Consumer<'T,'V>, pipelineIdx:int) = - inherit Truncate<'T, 'V>(takeCount, result, next, pipelineIdx) + and Take<'T,'V> (takeCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipelineIdx:int) = + inherit Truncate<'T, 'V>(takeCount, outOfBand, next, pipelineIdx) override this.OnComplete terminatingIdx = if terminatingIdx < pipelineIdx && this.Count < takeCount then @@ -899,14 +927,14 @@ namespace Microsoft.FSharp.Collections invalidOpFmt "tried to take {0} {1} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - and TakeWhile<'T,'V> (predicate:'T->bool, result:IPipeline, next:Consumer<'T,'V>, pipeIdx:int) = + and TakeWhile<'T,'V> (predicate:'T->bool, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = if predicate input then Helpers.avoidTailCall (next.ProcessNext input) else - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx false and Tail<'T, 'V> (next:Consumer<'T,'V>) = @@ -925,7 +953,7 @@ namespace Microsoft.FSharp.Collections if first then invalidArg "source" (SR.GetString(SR.notEnoughElements)) - and Truncate<'T,'V> (truncateCount:int, result:IPipeline, next:Consumer<'T,'V>, pipeIdx:int) = + and Truncate<'T,'V> (truncateCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = inherit SeqComponent<'T,'V>(next) let mutable count = 0 @@ -936,10 +964,10 @@ namespace Microsoft.FSharp.Collections if count < truncateCount then count <- count + 1 if count = truncateCount then - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx next.ProcessNext input else - result.StopFurtherProcessing pipeIdx + outOfBand.StopFurtherProcessing pipeIdx false type SeqProcessNextStates = @@ -954,7 +982,7 @@ namespace Microsoft.FSharp.Collections member val SeqState = SeqProcessNextStates.NotStarted with get, set member __.HaltedIdx = haltedIdx - interface IPipeline with + interface IOutOfBand with member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx // SetResult<> is used at the end of the chain of SeqComponents to assign the final value @@ -965,35 +993,35 @@ namespace Microsoft.FSharp.Collections result.Current <- input true - type Pipeline() = + type OutOfBand() = let mutable haltedIdx = 0 - interface IPipeline with member x.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx + interface IOutOfBand with member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx member __.HaltedIdx = haltedIdx module ForEach = - let enumerable (enumerable:IEnumerable<'T>) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = + let enumerable (enumerable:IEnumerable<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = use enumerator = enumerable.GetEnumerator () - while (pipeline.HaltedIdx = 0) && (enumerator.MoveNext ()) do + while (outOfBand.HaltedIdx = 0) && (enumerator.MoveNext ()) do consumer.ProcessNext enumerator.Current |> ignore - let array (array:array<'T>) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = + let array (array:array<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = let mutable idx = 0 - while (pipeline.HaltedIdx = 0) && (idx < array.Length) do + while (outOfBand.HaltedIdx = 0) && (idx < array.Length) do consumer.ProcessNext array.[idx] |> ignore idx <- idx + 1 - let list (alist:list<'T>) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = + let list (alist:list<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = let rec iterate lst = - match pipeline.HaltedIdx, lst with + match outOfBand.HaltedIdx, lst with | 0, hd :: tl -> consumer.ProcessNext hd |> ignore iterate tl | _ -> () iterate alist - let unfold (generator:'S->option<'T*'S>) state (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = + let unfold (generator:'S->option<'T*'S>) state (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = let rec iterate current = - match pipeline.HaltedIdx, generator current with + match outOfBand.HaltedIdx, generator current with | 0, Some (item, next) -> consumer.ProcessNext item |> ignore iterate next @@ -1006,11 +1034,11 @@ namespace Microsoft.FSharp.Collections | :? SeqComponent<'T,'U> as c -> c.Skipping | _ -> fun () -> false - let init f (terminatingIdx:int) (pipeline:Pipeline) (consumer:Consumer<'T,'U>) = + let init f (terminatingIdx:int) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = let mutable idx = -1 let isSkipping = makeIsSkipping consumer let mutable maybeSkipping = true - while (pipeline.HaltedIdx = 0) && (idx < terminatingIdx) do + while (outOfBand.HaltedIdx = 0) && (idx < terminatingIdx) do if maybeSkipping then maybeSkipping <- isSkipping () @@ -1019,16 +1047,16 @@ namespace Microsoft.FSharp.Collections idx <- idx + 1 - let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:SeqComponentFactory<'T,'U>) executeOn = - let pipeline = Pipeline() - let result = f (fun () -> (pipeline:>IPipeline).StopFurtherProcessing (current.PipeIdx+1)) + let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:ISeqFactory<'T,'U>) executeOn = + let pipeline = OutOfBand() + let result = f (fun () -> (pipeline:>IOutOfBand).StopFurtherProcessing (current.PipeIdx+1)) let consumer = current.Create pipeline emptyPipeIdx result try executeOn pipeline consumer - (Helpers.upcastISeqComponent consumer).OnComplete pipeline.HaltedIdx + (Helpers.upcastICompletionChaining consumer).OnComplete pipeline.HaltedIdx result finally - (Helpers.upcastISeqComponent consumer).OnDispose () + (Helpers.upcastICompletionChaining consumer).OnDispose () module Enumerable = type Empty<'T>() = @@ -1067,9 +1095,9 @@ namespace Microsoft.FSharp.Collections | _ -> failwith "library implementation error: all states should have been handled" and [] EnumerableBase<'T> () = - inherit SeqEnumerable<'T>() + let derivedClassShouldImplement () = + failwith "library implementation error: derived class should implement (should be abstract)" - abstract member Compose<'U> : (SeqComponentFactory<'T,'U>) -> IEnumerable<'U> abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> default this.Append source = Helpers.upcastEnumerable (AppendEnumerable [this; source]) @@ -1081,8 +1109,11 @@ namespace Microsoft.FSharp.Collections Helpers.upcastEnumeratorNonGeneric genericEnumerator interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = failwith "library implementation error: derived class should implement (should be abstract)" + member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement () + interface ISeq<'T> with + member __.Compose _ = derivedClassShouldImplement () + member __.ForEach _ = derivedClassShouldImplement () and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = inherit EnumeratorBase<'U>(result, seqComponent) @@ -1095,7 +1126,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete result.HaltedIdx + (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1108,9 +1139,9 @@ namespace Microsoft.FSharp.Collections try source.Dispose () finally - (Helpers.upcastISeqComponent seqComponent).OnDispose () + (Helpers.upcastICompletionChaining seqComponent).OnDispose () - and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqComponentFactory<'T,'U>) = + and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:ISeqFactory<'T,'U>) = inherit EnumerableBase<'U>() interface IEnumerable<'U> with @@ -1118,11 +1149,12 @@ namespace Microsoft.FSharp.Collections let result = Result<'U> () Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) - override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.upcastEnumerable (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) + interface ISeq<'U> with + member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + Helpers.upcastSeq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) - override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.enumerable enumerable) + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.enumerable enumerable) and ConcatEnumerator<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = let mutable state = SeqProcessNextStates.NotStarted @@ -1169,14 +1201,15 @@ namespace Microsoft.FSharp.Collections member this.GetEnumerator () : IEnumerator<'T> = Helpers.upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) - override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = - Helpers.upcastEnumerable (Enumerable<'T,'V>(this, next)) - override this.Append source = Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) - override this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable this) + interface ISeq<'T> with + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + Helpers.upcastSeq (Enumerable<'T,'V>(this, next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) and ConcatEnumerable<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = inherit EnumerableBase<'T>() @@ -1185,14 +1218,37 @@ namespace Microsoft.FSharp.Collections member this.GetEnumerator () : IEnumerator<'T> = Helpers.upcastEnumerator (new ConcatEnumerator<_,_> (sources)) - override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = - Helpers.upcastEnumerable (Enumerable<'T,'V>(this, next)) + interface ISeq<'T> with + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + Helpers.upcastSeq (Enumerable<'T,'V>(this, next)) - override this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable this) + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) let create enumerable current = - Helpers.upcastEnumerable (Enumerable(enumerable, current)) + Helpers.upcastSeq (Enumerable(enumerable, current)) + + module EmptyEnumerable = + type Enumerable<'T> () = + inherit Enumerable.EnumerableBase<'T>() + + static let singleton = Enumerable<'T>() :> ISeq<'T> + static member Instance = singleton + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>() + + override this.Append source = + Helpers.upcastEnumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) + + interface ISeq<'T> with + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + Helpers.upcastSeq (Enumerable.Enumerable<'T,'V>(this, next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) + + module Array = type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = @@ -1218,7 +1274,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete result.HaltedIdx + (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1226,7 +1282,7 @@ namespace Microsoft.FSharp.Collections initMoveNext () moveNext () - type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqComponentFactory<'T,'U>) = + type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:ISeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with @@ -1234,23 +1290,24 @@ namespace Microsoft.FSharp.Collections let result = Result<'U> () Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.upcastEnumerable (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) + interface ISeq<'U> with + member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + Helpers.upcastSeq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) - override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.array (delayedArray ())) + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.array (delayedArray ())) - let createDelayed (delayedArray:unit->array<'T>) (current:SeqComponentFactory<'T,'U>) = - Helpers.upcastEnumerable (Enumerable(delayedArray, current)) + let createDelayed (delayedArray:unit->array<'T>) (current:ISeqFactory<'T,'U>) = + Helpers.upcastSeq (Enumerable(delayedArray, current)) - let create (array:array<'T>) (current:SeqComponentFactory<'T,'U>) = + let create (array:array<'T>) (current:ISeqFactory<'T,'U>) = createDelayed (fun () -> array) current let createDelayedId (delayedArray:unit -> array<'T>) = - createDelayed delayedArray IdentityFactory.IdentityFactory + createDelayed delayedArray IdentityFactory.Instance let createId (array:array<'T>) = - create array IdentityFactory.IdentityFactory + create array IdentityFactory.Instance module List = type Enumerator<'T,'U>(alist:list<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = @@ -1268,7 +1325,7 @@ namespace Microsoft.FSharp.Collections moveNext tail | _ -> result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete result.HaltedIdx + (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1276,7 +1333,7 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext list - type Enumerable<'T,'U>(alist:list<'T>, current:SeqComponentFactory<'T,'U>) = + type Enumerable<'T,'U>(alist:list<'T>, current:ISeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with @@ -1284,23 +1341,24 @@ namespace Microsoft.FSharp.Collections let result = Result<'U> () Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - override __.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.upcastEnumerable (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) + interface ISeq<'U> with + member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + Helpers.upcastSeq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) - override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.list alist) + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.list alist) let create alist current = - Helpers.upcastEnumerable (Enumerable(alist, current)) + Helpers.upcastSeq (Enumerable(alist, current)) module Unfold = - type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, signal:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) + type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let mutable current = state let rec moveNext () = - match signal.HaltedIdx, generator current with + match result.HaltedIdx, generator current with | 0, Some (item, nextState) -> current <- nextState if seqComponent.ProcessNext item then @@ -1311,10 +1369,10 @@ namespace Microsoft.FSharp.Collections interface IEnumerator with member __.MoveNext () = - signal.SeqState <- SeqProcessNextStates.InProcess + result.SeqState <- SeqProcessNextStates.InProcess moveNext () - type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqComponentFactory<'T,'U>) = + type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:ISeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with @@ -1322,11 +1380,12 @@ namespace Microsoft.FSharp.Collections let result = Result<'U> () Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.upcastEnumerable (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + interface ISeq<'U> with + member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + Helpers.upcastSeq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) - override this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.unfold generator state) + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.unfold generator state) module Init = // The original implementation of "init" delayed the calculation of Current, and so it was possible @@ -1348,8 +1407,8 @@ namespace Microsoft.FSharp.Collections else System.Int32.MaxValue - type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:Consumer<'T,'U>, signal:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(signal, seqComponent) + type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) let isSkipping = ForEach.makeIsSkipping seqComponent @@ -1361,7 +1420,7 @@ namespace Microsoft.FSharp.Collections let mutable idx = -1 let rec moveNext () = - if (signal.HaltedIdx = 0) && idx < terminatingIdx then + if (result.HaltedIdx = 0) && idx < terminatingIdx then idx <- idx + 1 if maybeSkipping then @@ -1375,19 +1434,19 @@ namespace Microsoft.FSharp.Collections true else moveNext () - elif (signal.HaltedIdx = 0) && idx = System.Int32.MaxValue then + elif (result.HaltedIdx = 0) && idx = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) else - signal.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastISeqComponent seqComponent).OnComplete signal.HaltedIdx + result.SeqState <- SeqProcessNextStates.Finished + (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with member __.MoveNext () = - signal.SeqState <- SeqProcessNextStates.InProcess + result.SeqState <- SeqProcessNextStates.InProcess moveNext () - type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqComponentFactory<'T,'U>) = + type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:ISeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with @@ -1395,12 +1454,13 @@ namespace Microsoft.FSharp.Collections let result = Result<'U> () Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - override this.Compose (next:SeqComponentFactory<'U,'V>) : IEnumerable<'V> = - Helpers.upcastEnumerable (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + interface ISeq<'U> with + member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + Helpers.upcastSeq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) - override this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = - let terminatingIdx = getTerminatingIdx count - ForEach.execute createResult current (ForEach.init f terminatingIdx) + member this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = + let terminatingIdx = getTerminatingIdx count + ForEach.execute createResult current (ForEach.init f terminatingIdx) let upto lastOption f = match lastOption with @@ -1462,11 +1522,172 @@ namespace Microsoft.FSharp.Collections // in the way presented, but it's possible. upto (if count.HasValue then Some (count.Value-1) else None) f - override this.Compose (next:SeqComponentFactory<'T,'U>) : IEnumerable<'U> = - Helpers.upcastEnumerable (Enumerable<'T,'V>(count, f, next)) + interface ISeq<'T> with + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + Helpers.upcastSeq (Enumerable<'T,'V>(count, f, next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (Helpers.upcastEnumerable this)) + + open RuntimeHelpers + + [] + let toComposer (source:seq<'T>) : ISeq<'T> = + checkNonNull "source" source + match source with + | :? ISeq<'T> as s -> s + | :? array<'T> as a -> Helpers.upcastSeq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) + | :? list<'T> as a -> Helpers.upcastSeq (List.Enumerable(a, IdentityFactory.Instance)) + | _ -> Helpers.upcastSeq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) + + let inline foreach f (source:ISeq<_>) = + source.ForEach f + + let inline compose factory (source:ISeq<'T>) = + source.Compose factory + + [] + let empty<'T> = EmptyEnumerable.Enumerable<'T>.Instance + + [] + let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> = + Helpers.upcastSeq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) + + [] + let initInfinite<'T> (f:int->'T) : ISeq<'T> = + Helpers.upcastSeq (new Init.EnumerableDecider<'T>(Nullable (), f)) + + [] + let init<'T> (count:int) (f:int->'T) : ISeq<'T> = + if count < 0 then invalidArgInputMustBeNonNegative "count" count + elif count = 0 then empty else + Helpers.upcastSeq (new Init.EnumerableDecider<'T>(Nullable count, f)) + + [] + let iter f (source:ISeq<'T>) = + source + |> foreach (fun _ -> + { new Consumer<'T,'T> () with + override this.ProcessNext value = + f value + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> ignore + + [] + let tryItem i (source:ISeq<'T>) = + if i < 0 then None else + source + |> foreach (fun halt -> + { new Folder<'T, Values>> (Values<_,_> (0, None)) with + override this.ProcessNext value = + if this.Value._1 = i then + this.Value._2 <- Some value + halt () + else + this.Value._1 <- this.Value._1 + 1 + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun item -> item.Value._2 + + [] + let iteri f (source:ISeq<'T>) = + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f + + source + |> foreach (fun _ -> + { new Folder<'T, int> (0) with + override this.ProcessNext value = + f.Invoke(this.Value, value) + this.Value <- this.Value + 1 + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> ignore + + [] + let exists f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, bool> (false) with + override this.ProcessNext value = + if f value then + this.Value <- true + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun exists -> exists.Value + + [] + let inline contains element (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, bool> (false) with + override this.ProcessNext value = + if element = value then + this.Value <- true + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun contains -> contains.Value + + [] + let forall f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, bool> (true) with + override this.ProcessNext value = + if not (f value) then + this.Value <- false + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun forall -> forall.Value + + [] + let filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = + source + |> compose (FilterFactory f) + + [] + let map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = + source + |> compose (MapFactory f) + + [] + let mapi f source = + source + |> compose (MapiFactory f) + + [] + let choose f source = + source + |> compose (ChooseFactory f) + + [] + let indexed source = + source + |> compose (MapiFactory (fun i x -> i,x)) + + [] + let tryPick f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, Option<'U>> (None) with + override this.ProcessNext value = + match f value with + | (Some _) as some -> + this.Value <- some + halt () + | None -> () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun pick -> pick.Value + + [] + let tryFind f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, Option<'T>> (None) with + override this.ProcessNext value = + if f value then + this.Value <- Some value + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun find -> find.Value - override this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.IdentityFactory (ForEach.enumerable (Helpers.upcastEnumerable this)) #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions @@ -1476,18 +1697,11 @@ namespace Microsoft.FSharp.Collections let inline indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) [] - let toComposer (source:seq<'T>): Composer.Internal.SeqEnumerable<'T> = - checkNonNull "source" source - match source with - | :? Composer.Enumerable.EnumerableBase<'T> as s -> upcast s - | :? array<'T> as a -> upcast Composer.Array.Enumerable((fun () -> a), Composer.IdentityFactory.IdentityFactory) - | :? list<'T> as a -> upcast Composer.List.Enumerable(a, Composer.IdentityFactory.IdentityFactory) - | _ -> upcast Composer.Enumerable.Enumerable<'T,'T>(source, Composer.IdentityFactory.IdentityFactory) + let toComposer (source:seq<'T>): Composer.Internal.ISeq<'T> = + Composer.toComposer source let inline foreach f (source:seq<_>) = - source - |> toComposer - |> fun composer -> composer.ForEach f + Composer.foreach f (toComposer source) let inline foreach f (source:seq<_>) = Composer.Seq.foreach f (toComposer source) @@ -1505,30 +1719,25 @@ namespace Microsoft.FSharp.Collections [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> = - Composer.Helpers.upcastEnumerable (new Composer.Unfold.Enumerable<'T,'T,'State>(generator, state, Composer.IdentityFactory.IdentityFactory)) + Composer.unfold generator state + |> Composer.Helpers.upcastEnumerable [] let empty<'T> = (EmptyEnumerable :> seq<'T>) [] let initInfinite<'T> (f:int->'T) : IEnumerable<'T> = - Composer.Helpers.upcastEnumerable (new Composer.Init.EnumerableDecider<'T>(Nullable (), f)) + Composer.initInfinite f + |> Composer.Helpers.upcastEnumerable [] let init<'T> (count:int) (f:int->'T) : IEnumerable<'T> = - if count < 0 then invalidArgInputMustBeNonNegative "count" count - elif count = 0 then empty else - Composer.Helpers.upcastEnumerable (new Composer.Init.EnumerableDecider<'T>(Nullable count, f)) + Composer.init count f + |> Composer.Helpers.upcastEnumerable [] let iter f (source : seq<'T>) = - source - |> foreach (fun _ -> - { new Composer.Internal.Consumer<'T,'T> () with - override this.ProcessNext value = - f value - Unchecked.defaultof }) - |> ignore + Composer.iter f (toComposer source) [] let tryHead (source : seq<_>) = @@ -1551,73 +1760,27 @@ namespace Microsoft.FSharp.Collections | Some value -> value [] - let tryItem i (source : seq<'T>) = - if i < 0 then None else - source - |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values>> (Composer.Internal.Values<_, _> (0, None)) with - override this.ProcessNext value = - if this.Value._1 = i then - this.Value._2 <- Some value - halt () - else - this.Value._1 <- this.Value._1 + 1 - Unchecked.defaultof }) - |> fun item -> item.Value._2 + let tryItem i (source:seq<'T>) = + Composer.tryItem i (toComposer source) [] let nth i (source : seq<'T>) = item i source [] - let iteri f (source : seq<'T>) = - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - source - |> foreach (fun _ -> - { new Composer.Internal.Folder<'T, int> (0) with - override this.ProcessNext value = - f.Invoke(this.Value, value) - this.Value <- this.Value + 1 - Unchecked.defaultof }) - |> ignore + let iteri f (source:seq<'T>) = + Composer.iteri f (toComposer source) [] - let exists f (source : seq<'T>) = - source - |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, bool> (false) with - override this.ProcessNext value = - if f value then - this.Value <- true - halt () - Unchecked.defaultof - }) - |> fun exists -> exists.Value + let exists f (source:seq<'T>) = + Composer.exists f (toComposer source) [] - let inline contains element (source : seq<'T>) = - source - |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, bool> (false) with - override this.ProcessNext value = - if element = value then - this.Value <- true - halt () - Unchecked.defaultof - }) - |> fun contains -> contains.Value + let inline contains element (source:seq<'T>) = + Composer.contains element (toComposer source) [] - let forall f (source : seq<'T>) = - source - |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, bool> (true) with - override this.ProcessNext value = - if not (f value) then - this.Value <- false - halt () - Unchecked.defaultof - }) - |> fun forall -> forall.Value + let forall f (source:seq<'T>) = + Composer.forall f (toComposer source) [] let iter2 f (source1 : seq<_>) (source2 : seq<_>) = @@ -1666,25 +1829,28 @@ namespace Microsoft.FSharp.Collections let private seqFactory createSeqComponent (source:seq<'T>) = checkNonNull "source" source match source with - | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Compose createSeqComponent - | :? array<'T> as a -> Composer.Array.create a createSeqComponent - | :? list<'T> as a -> Composer.List.create a createSeqComponent - | _ -> Composer.Enumerable.create source createSeqComponent + | :? Composer.Internal.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose createSeqComponent) + | :? array<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.Array.create a createSeqComponent) + | :? list<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.List.create a createSeqComponent) + | _ -> Composer.Helpers.upcastEnumerable (Composer.Enumerable.create source createSeqComponent) [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = - source |> seqFactory (Composer.FilterFactory f) + Composer.filter f (toComposer source) + |> Composer.Helpers.upcastEnumerable [] let where f source = filter f source [] let map<'T,'U> (f:'T->'U) (source:seq<'T>) : seq<'U> = - source |> seqFactory (Composer.MapFactory f) + Composer.map f (toComposer source) + |> Composer.Helpers.upcastEnumerable [] let mapi f source = - source |> seqFactory (Composer.MapiFactory f) + Composer.mapi f (toComposer source) + |> Composer.Helpers.upcastEnumerable [] let mapi2 f source1 source2 = @@ -1695,7 +1861,7 @@ namespace Microsoft.FSharp.Collections let map2<'T,'U,'V> (f:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = checkNonNull "source1" source1 match source1 with - | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Compose (Composer.Map2FirstFactory (f, source2)) + | :? Composer.Internal.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose (Composer.Map2FirstFactory (f, source2))) | _ -> source2 |> seqFactory (Composer.Map2SecondFactory (f, source1)) [] @@ -1705,12 +1871,14 @@ namespace Microsoft.FSharp.Collections source1 |> seqFactory (Composer.Map3Factory (f, source2, source3)) [] - let choose f source = - source |> seqFactory (Composer.ChooseFactory f) + let choose f source = + Composer.choose f (toComposer source) + |> Composer.Helpers.upcastEnumerable [] let indexed source = - source |> seqFactory (Composer.MapiFactory (fun i x -> i,x) ) + Composer.indexed (toComposer source) + |> Composer.Helpers.upcastEnumerable [] let zip source1 source2 = @@ -1727,17 +1895,7 @@ namespace Microsoft.FSharp.Collections [] let tryPick f (source : seq<'T>) = - source - |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Option<'U>> (None) with - override this.ProcessNext value = - match f value with - | (Some _) as some -> - this.Value <- some - halt () - | None -> () - Unchecked.defaultof }) - |> fun pick -> pick.Value + Composer.tryPick f (toComposer source) [] let pick f source = @@ -1747,15 +1905,7 @@ namespace Microsoft.FSharp.Collections [] let tryFind f (source : seq<'T>) = - source - |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Option<'T>> (None) with - override this.ProcessNext value = - if f value then - this.Value <- Some value - halt () - Unchecked.defaultof }) - |> fun find -> find.Value + Composer.tryFind f (toComposer source) [] let find f source = @@ -1809,7 +1959,7 @@ namespace Microsoft.FSharp.Collections { new Composer.Internal.Folder<'T,'State> (x) with override this.ProcessNext value = this.Value <- f.Invoke (this.Value, value) - Unchecked.defaultof }) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun folded -> folded.Value source @@ -1851,7 +2001,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- value else this.Value._2 <- f.Invoke (this.Value._2, value) - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._1 then @@ -1881,34 +2031,24 @@ namespace Microsoft.FSharp.Collections use e2 = source2.GetEnumerator() let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let mutable e2ok = Unchecked.defaultof source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values<_,_>(false, 0)) with + { new Composer.Internal.Folder<'T,int> (0) with override this.ProcessNext value = - e2ok <- e2.MoveNext() - if not e2ok then - this.Value._1 <- true - this.Value._2 <- 1 + if not (e2.MoveNext()) then + this.Value <- 1 halt () else - let c = f.Invoke(value, e2.Current) + let c = f.Invoke (value, e2.Current) if c <> 0 then - this.Value._1 <- true - this.Value._2 <- c + this.Value <- c halt () - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = - if not this.Value._1 then - e2ok <- e2.MoveNext() - if e2ok then - this.Value._2 <- -1 - else - this.Value._2 <- 0 - - }) - |> fun compare -> compare.Value._2 + if this.Value = 0 && e2.MoveNext() then + this.Value <- -1 }) + |> fun compare -> compare.Value [] let ofList (source : 'T list) = @@ -1923,7 +2063,7 @@ namespace Microsoft.FSharp.Collections [] let ofArray (source : 'T array) = checkNonNull "source" source - Composer.Array.createId source + Composer.Helpers.upcastEnumerable (Composer.Array.createId source) [] let toArray (source : seq<'T>) = @@ -2018,8 +2158,7 @@ namespace Microsoft.FSharp.Collections halt () else this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof - }) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun tried -> tried.Value._1 [] @@ -2174,7 +2313,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceBy keyf array array - Composer.Array.createDelayedId delayedSort + Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedSort) [] let sort source = @@ -2183,7 +2322,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlace array array - Composer.Array.createDelayedId delayedSort + Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedSort) [] let sortWith f source = @@ -2192,7 +2331,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceWith f array array - Composer.Array.createDelayedId delayedSort + Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedSort) [] let inline sortByDescending keyf source = @@ -2246,7 +2385,7 @@ namespace Microsoft.FSharp.Collections { new Composer.Internal.Folder<'a,'a> (LanguagePrimitives.GenericZero) with override this.ProcessNext value = this.Value <- Checked.(+) this.Value value - Unchecked.defaultof }) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun sum -> sum.Value [] @@ -2256,7 +2395,7 @@ namespace Microsoft.FSharp.Collections { new Composer.Internal.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with override this.ProcessNext value = this.Value <- Checked.(+) this.Value (f value) - Unchecked.defaultof }) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun sum -> sum.Value [] @@ -2267,7 +2406,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 value this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._2 = 0 then @@ -2282,7 +2421,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 (f value) this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._2 = 0 then @@ -2305,7 +2444,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- value elif value < this.Value._2 then this.Value._2 <- value - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._1 then @@ -2328,7 +2467,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- valueU this.Value._3 <- value | _ -> () - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._1 then @@ -2363,7 +2502,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- value elif value > this.Value._2 then this.Value._2 <- value - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._1 then @@ -2386,7 +2525,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- valueU this.Value._3 <- value | _ -> () - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._1 then @@ -2445,7 +2584,7 @@ namespace Microsoft.FSharp.Collections override this.ProcessNext value = this.Value <- Some value halt () - Unchecked.defaultof }) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun head -> head.Value source1 @@ -2480,7 +2619,7 @@ namespace Microsoft.FSharp.Collections if this.Value._1 then this.Value._1 <- false this.Value._2 <- value - Unchecked.defaultof }) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun tried -> if tried.Value._1 then None @@ -2505,7 +2644,7 @@ namespace Microsoft.FSharp.Collections else this.Value._3 <- true halt () - Unchecked.defaultof + Unchecked.defaultof<_> (* return value unsed in ForEach context *) member this.OnComplete _ = if this.Value._1 then @@ -2528,7 +2667,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.Reverse array array - Composer.Array.createDelayedId delayedReverse + Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedReverse) [] let permute f (source:seq<_>) = @@ -2537,7 +2676,7 @@ namespace Microsoft.FSharp.Collections source |> toArray |> Array.permute f - Composer.Array.createDelayedId delayedPermute + Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedPermute) [] let mapFold<'T,'State,'Result> (f: 'State -> 'T -> 'Result * 'State) acc source = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index b554294d6d8..a84a71fc037 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -18,6 +18,7 @@ namespace Microsoft.FSharp.Collections /// PipeIdx denotes the index of the element within the pipeline. 0 denotes the /// source of the chain. type PipeIdx = int + type ``PipeIdx?`` = Nullable /// ICompletionChaining is used to correctly handle cleaning up of the pipeline. A /// base implementation is provided in Consumer, and should not be overwritten. Consumer @@ -34,6 +35,9 @@ namespace Microsoft.FSharp.Collections /// after the enumeration has completed. abstract OnDispose : unit -> unit + type IOutOfBand = + abstract StopFurtherProcessing : PipeIdx -> unit + /// Consumer is the base class of all elements within the pipeline [] type Consumer<'T,'U> = @@ -69,10 +73,14 @@ namespace Microsoft.FSharp.Collections new : init:'U -> Folder<'T,'U> val mutable Value: 'U - /// SeqEnumerable functions provide the enhance seq experience - [] - type SeqEnumerable<'T> = - abstract member ForEach<'a when 'a :> Consumer<'T,'T>> : f:((unit->unit)->'a) -> 'a + type ISeqFactory<'T,'U> = + abstract member Create : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> + abstract member PipeIdx : PipeIdx + + type ISeq<'T> = + inherit System.Collections.Generic.IEnumerable<'T> + abstract member Compose : ISeqFactory<'T,'U> -> ISeq<'U> + abstract member ForEach : f:((unit -> unit) -> 'a) -> 'a when 'a :> Consumer<'T,'T> /// Returns a new sequence that contains the cartesian product of the two input sequences. /// The first sequence. @@ -1265,7 +1273,7 @@ namespace Microsoft.FSharp.Collections /// /// Thrown when the input sequence is null. [] - val toComposer : source:seq<'T> -> Composer.Internal.SeqEnumerable<'T> + val toComposer : source:seq<'T> -> Composer.Internal.ISeq<'T> /// Builds a list from the given collection. /// From 9e3f75342e661da22e4e3e296ebf550ba9c6522c Mon Sep 17 00:00:00 2001 From: liboz Date: Sat, 29 Oct 2016 22:26:16 -0400 Subject: [PATCH 47/59] Seq.item/iter2/iteri2/fold2/forall2/exists2 --- src/fsharp/FSharp.Core/seq.fs | 63 ++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index ea249208d6d..36116e3bc7e 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -1752,12 +1752,25 @@ namespace Microsoft.FSharp.Collections [] let item i (source : seq<'T>) = if i < 0 then invalidArgInputMustBeNonNegative "index" i else - source - |> seqFactory (Composer.Seq.SkipFactory (i, invalidArgumnetIndex)) - |> tryHead - |> function - | None -> invalidArgFmt "index" "{0}\nseq was short by 1 element" [|SR.GetString SR.notEnoughElements|] - | Some value -> value + source + |> foreach (fun halt -> + { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values<_,_,_> (0, false, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 = i then + this.Value._2 <- true + this.Value._3 <- value + halt () + else + this.Value._1 <- this.Value._1 + 1 + Unchecked.defaultof<_> (* return value unsed in ForEach context *) + override this.OnComplete _ = + if not this.Value._2 then + let index = i - this.Value._1 + 1 + invalidArgFmt "index" + "{0}\nseq was short by {1} {2}" + [|SR.GetString SR.notEnoughElements; index; (if index=1 then "element" else "elements")|] + }) + |> fun item -> item.Value._3 [] let tryItem i (source:seq<'T>) = @@ -1791,7 +1804,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Core.Folder<_,_> () with + { new Composer.Internal.Folder<_,_> () with override this.ProcessNext value = if (e2.MoveNext()) then f.Invoke(value, e2.Current) @@ -1809,7 +1822,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Core.Folder<_,int> (0) with + { new Composer.Internal.Folder<_,int> (0) with override this.ProcessNext value = if (e2.MoveNext()) then f.Invoke(this.Value, value, e2.Current) @@ -1979,7 +1992,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Core.Folder<_,'State> (state) with + { new Composer.Internal.Folder<_,'State> (state) with override this.ProcessNext value = if (e2.MoveNext()) then this.Value <- f.Invoke(this.Value, value, e2.Current) @@ -2011,7 +2024,13 @@ namespace Microsoft.FSharp.Collections [] let replicate count x = + #if FX_ATLEAST_40 System.Linq.Enumerable.Repeat(x,count) + #else + if count < 0 then invalidArg "count" (SR.GetString(SR.inputMustBeNonNegative)) + seq { for _ in 1 .. count -> x } + #endif + [] let append (source1: seq<'T>) (source2: seq<'T>) = @@ -2569,12 +2588,38 @@ namespace Microsoft.FSharp.Collections use e2 = source2.GetEnumerator() let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(p) + source1 + |> foreach (fun halt -> + { new Composer.Internal.Folder<_,bool> (true) with + override this.ProcessNext value = + if (e2.MoveNext()) then + if not (p.Invoke(value, e2.Current)) then + this.Value <- false + halt() + else + halt() + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun all -> all.Value + [] let exists2 p (source1: seq<_>) (source2: seq<_>) = checkNonNull "source2" source2 use e2 = source2.GetEnumerator() let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(p) + + source1 + |> foreach (fun halt -> + { new Composer.Internal.Folder<_,bool> (false) with + override this.ProcessNext value = + if (e2.MoveNext()) then + if p.Invoke(value, e2.Current) then + this.Value <- true + halt() + else + halt() + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun exists -> exists.Value [] let tryHead (source : seq<_>) = From a134bf885a08047b311c552f2f0052a77ca76a7a Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sun, 30 Oct 2016 04:56:56 +0100 Subject: [PATCH 48/59] Removed Helpers. qualifier Names are unique and descriptive enough Adding types to try to appease test Adding the types doesn't work. Only appearing in portable build, so pondering if it is a compiler bug? Will need to get onto someone about it I think. --- src/fsharp/FSharp.Core/seq.fs | 128 +++++++++++++++++----------------- 1 file changed, 65 insertions(+), 63 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 36116e3bc7e..9f19891ccc6 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -547,12 +547,14 @@ namespace Microsoft.FSharp.Collections let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) let inline upcastICompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) + open Helpers + type [] SeqComponentFactory<'T,'U> (pipeIdx:``PipeIdx?``) = new() = SeqComponentFactory<'T,'U> (emptyPipeIdx) interface ISeqFactory<'T,'U> with member __.PipeIdx = getPipeIdx pipeIdx - member __.Create _ _ _ = failwith "library implementation error: Create on base factory should not be called" + member __.Create<'V> (_:IOutOfBand) (_:``PipeIdx?``) (_:Consumer<'U,'V>) : Consumer<'T,'V> = failwith "library implementation error: Create on base factory should not be called" and ComposedFactory<'T,'U,'V> private (first:ISeqFactory<'T,'U>, second:ISeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = inherit SeqComponentFactory<'T,'V> (makePipeIdx secondPipeIdx) @@ -562,7 +564,7 @@ namespace Microsoft.FSharp.Collections first.Create outOfBand pipeIdx (second.Create outOfBand (makePipeIdx secondPipeIdx) next) static member Combine (first:ISeqFactory<'T,'U>) (second:ISeqFactory<'U,'V>) : ISeqFactory<'T,'V> = - ComposedFactory(first, second, first.PipeIdx+1) |> Helpers.upcastFactory + ComposedFactory(first, second, first.PipeIdx+1) |> upcastFactory and ChooseFactory<'T,'U> (filter:'T->option<'U>) = inherit SeqComponentFactory<'T,'U> () @@ -700,7 +702,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = match choose input with - | Some value -> Helpers.avoidTailCall (next.ProcessNext value) + | Some value -> avoidTailCall (next.ProcessNext value) | None -> false and Distinct<'T,'V when 'T: equality> (next:Consumer<'T,'V>) = @@ -710,7 +712,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if hashSet.Add input then - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else false @@ -721,7 +723,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if hashSet.Add(keyFunction input) then - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else false @@ -732,7 +734,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if cached.Value.Add input then - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else false @@ -743,7 +745,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if filter input then - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else false @@ -752,7 +754,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if filter input then - Helpers.avoidTailCall (next.ProcessNext (map input)) + avoidTailCall (next.ProcessNext (map input)) else false @@ -762,7 +764,7 @@ namespace Microsoft.FSharp.Collections override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) override __.ProcessNext (input:'T) : bool = - Helpers.avoidTailCall (next.ProcessNext (map input)) + avoidTailCall (next.ProcessNext (map input)) and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = inherit SeqComponent<'First,'V>(next) @@ -772,7 +774,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'First) : bool = if input2.MoveNext () then - Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) + avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -788,7 +790,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'Second) : bool = if input1.MoveNext () then - Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) + avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -805,7 +807,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'First) : bool = if input2.MoveNext () && input3.MoveNext () then - Helpers.avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) + avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -820,7 +822,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = let u = map input if filter u then - Helpers.avoidTailCall (next.ProcessNext u) + avoidTailCall (next.ProcessNext u) else false @@ -832,7 +834,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = idx <- idx + 1 - Helpers.avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) + avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = inherit SeqComponent<'First,'V>(next) @@ -844,7 +846,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'First) : bool = if input2.MoveNext () then idx <- idx + 1 - Helpers.avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) + avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -866,7 +868,7 @@ namespace Microsoft.FSharp.Collections else let currentPair = lastValue, input lastValue <- input - Helpers.avoidTailCall (next.ProcessNext currentPair) + avoidTailCall (next.ProcessNext currentPair) and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:Consumer<'State,'V>) = inherit SeqComponent<'T,'V>(next) @@ -876,7 +878,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = foldResult <- f.Invoke(foldResult, input) - Helpers.avoidTailCall (next.ProcessNext foldResult) + avoidTailCall (next.ProcessNext foldResult) and Skip<'T,'V> (skipCount:int, next:Consumer<'T,'V>) = inherit SeqComponent<'T,'V>(next) @@ -895,7 +897,7 @@ namespace Microsoft.FSharp.Collections count <- count + 1 false else - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) override __.OnComplete _ = if count < skipCount then @@ -914,9 +916,9 @@ namespace Microsoft.FSharp.Collections if skip then false else - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) and Take<'T,'V> (takeCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipelineIdx:int) = inherit Truncate<'T, 'V>(takeCount, outOfBand, next, pipelineIdx) @@ -932,7 +934,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'T) : bool = if predicate input then - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else outOfBand.StopFurtherProcessing pipeIdx false @@ -947,7 +949,7 @@ namespace Microsoft.FSharp.Collections first <- false false else - Helpers.avoidTailCall (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) override this.OnComplete _ = if first then @@ -965,7 +967,7 @@ namespace Microsoft.FSharp.Collections count <- count + 1 if count = truncateCount then outOfBand.StopFurtherProcessing pipeIdx - next.ProcessNext input + avoidTailCall (next.ProcessNext input) else outOfBand.StopFurtherProcessing pipeIdx false @@ -1053,10 +1055,10 @@ namespace Microsoft.FSharp.Collections let consumer = current.Create pipeline emptyPipeIdx result try executeOn pipeline consumer - (Helpers.upcastICompletionChaining consumer).OnComplete pipeline.HaltedIdx + (upcastICompletionChaining consumer).OnComplete pipeline.HaltedIdx result finally - (Helpers.upcastICompletionChaining consumer).OnDispose () + (upcastICompletionChaining consumer).OnDispose () module Enumerable = type Empty<'T>() = @@ -1081,7 +1083,7 @@ namespace Microsoft.FSharp.Collections seqComponent.OnDispose () interface IEnumerator with - member this.Current : obj = box ((Helpers.upcastEnumerator this)).Current + member this.Current : obj = box ((upcastEnumerator this)).Current member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)" member __.Reset () : unit = noReset () @@ -1100,13 +1102,13 @@ namespace Microsoft.FSharp.Collections abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> - default this.Append source = Helpers.upcastEnumerable (AppendEnumerable [this; source]) + default this.Append source = upcastEnumerable (AppendEnumerable [this; source]) interface IEnumerable with member this.GetEnumerator () : IEnumerator = - let genericEnumerable = Helpers.upcastEnumerable this + let genericEnumerable = upcastEnumerable this let genericEnumerator = genericEnumerable.GetEnumerator () - Helpers.upcastEnumeratorNonGeneric genericEnumerator + upcastEnumeratorNonGeneric genericEnumerator interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement () @@ -1126,7 +1128,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1139,7 +1141,7 @@ namespace Microsoft.FSharp.Collections try source.Dispose () finally - (Helpers.upcastICompletionChaining seqComponent).OnDispose () + (upcastICompletionChaining seqComponent).OnDispose () and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:ISeqFactory<'T,'U>) = inherit EnumerableBase<'U>() @@ -1147,11 +1149,11 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - Helpers.upcastSeq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) + upcastSeq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.enumerable enumerable) @@ -1183,7 +1185,7 @@ namespace Microsoft.FSharp.Collections | _ -> failwith "library implementation error: all states should have been handled" interface IEnumerator with - member this.Current = box ((Helpers.upcastEnumerator this)).Current + member this.Current = box ((upcastEnumerator this)).Current member __.MoveNext () = state <- SeqProcessNextStates.InProcess moveNext () @@ -1199,14 +1201,14 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = - Helpers.upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) + upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) override this.Append source = - Helpers.upcastEnumerable (AppendEnumerable (source :: sources)) + upcastEnumerable (AppendEnumerable (source :: sources)) interface ISeq<'T> with member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - Helpers.upcastSeq (Enumerable<'T,'V>(this, next)) + upcastSeq (Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) @@ -1216,17 +1218,17 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = - Helpers.upcastEnumerator (new ConcatEnumerator<_,_> (sources)) + upcastEnumerator (new ConcatEnumerator<_,_> (sources)) interface ISeq<'T> with member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - Helpers.upcastSeq (Enumerable<'T,'V>(this, next)) + upcastSeq (Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) let create enumerable current = - Helpers.upcastSeq (Enumerable(enumerable, current)) + upcastSeq (Enumerable(enumerable, current)) module EmptyEnumerable = type Enumerable<'T> () = @@ -1239,11 +1241,11 @@ namespace Microsoft.FSharp.Collections member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>() override this.Append source = - Helpers.upcastEnumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) + upcastEnumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) interface ISeq<'T> with member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - Helpers.upcastSeq (Enumerable.Enumerable<'T,'V>(this, next)) + upcastSeq (Enumerable.Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) @@ -1274,7 +1276,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1288,17 +1290,17 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - Helpers.upcastSeq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) + upcastSeq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.array (delayedArray ())) let createDelayed (delayedArray:unit->array<'T>) (current:ISeqFactory<'T,'U>) = - Helpers.upcastSeq (Enumerable(delayedArray, current)) + upcastSeq (Enumerable(delayedArray, current)) let create (array:array<'T>) (current:ISeqFactory<'T,'U>) = createDelayed (fun () -> array) current @@ -1325,7 +1327,7 @@ namespace Microsoft.FSharp.Collections moveNext tail | _ -> result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1339,17 +1341,17 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - Helpers.upcastSeq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) + upcastSeq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.list alist) let create alist current = - Helpers.upcastSeq (Enumerable(alist, current)) + upcastSeq (Enumerable(alist, current)) module Unfold = type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, result:Result<'U>) = @@ -1378,11 +1380,11 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - Helpers.upcastSeq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + upcastSeq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.unfold generator state) @@ -1438,7 +1440,7 @@ namespace Microsoft.FSharp.Collections raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) else result.SeqState <- SeqProcessNextStates.Finished - (Helpers.upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -1452,11 +1454,11 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Helpers.upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - Helpers.upcastSeq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + upcastSeq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) member this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = let terminatingIdx = getTerminatingIdx count @@ -1524,10 +1526,10 @@ namespace Microsoft.FSharp.Collections interface ISeq<'T> with member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - Helpers.upcastSeq (Enumerable<'T,'V>(count, f, next)) + upcastSeq (Enumerable<'T,'V>(count, f, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (Helpers.upcastEnumerable this)) + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (upcastEnumerable this)) open RuntimeHelpers @@ -1536,9 +1538,9 @@ namespace Microsoft.FSharp.Collections checkNonNull "source" source match source with | :? ISeq<'T> as s -> s - | :? array<'T> as a -> Helpers.upcastSeq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) - | :? list<'T> as a -> Helpers.upcastSeq (List.Enumerable(a, IdentityFactory.Instance)) - | _ -> Helpers.upcastSeq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) + | :? array<'T> as a -> upcastSeq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) + | :? list<'T> as a -> upcastSeq (List.Enumerable(a, IdentityFactory.Instance)) + | _ -> upcastSeq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) let inline foreach f (source:ISeq<_>) = source.ForEach f @@ -1551,17 +1553,17 @@ namespace Microsoft.FSharp.Collections [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> = - Helpers.upcastSeq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) + upcastSeq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) [] let initInfinite<'T> (f:int->'T) : ISeq<'T> = - Helpers.upcastSeq (new Init.EnumerableDecider<'T>(Nullable (), f)) + upcastSeq (new Init.EnumerableDecider<'T>(Nullable (), f)) [] let init<'T> (count:int) (f:int->'T) : ISeq<'T> = if count < 0 then invalidArgInputMustBeNonNegative "count" count elif count = 0 then empty else - Helpers.upcastSeq (new Init.EnumerableDecider<'T>(Nullable count, f)) + upcastSeq (new Init.EnumerableDecider<'T>(Nullable count, f)) [] let iter f (source:ISeq<'T>) = From a7dc52cca6b30c0cad5fc1fb576ea427fd796206 Mon Sep 17 00:00:00 2001 From: liboz Date: Mon, 31 Oct 2016 19:40:51 -0400 Subject: [PATCH 49/59] seq.windowed --- src/fsharp/FSharp.Core/seq.fs | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 9f19891ccc6..c688866dae6 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -673,6 +673,11 @@ namespace Microsoft.FSharp.Collections inherit SeqComponentFactory<'T,'T> () interface ISeqFactory<'T,'T> with member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, getPipeIdx pipeIdx) + + and WindowedFactory<'T> (windowSize:int) = + inherit SeqComponentFactory<'T, 'T[]> () + interface ISeqFactory<'T, 'T[]> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T[],'V>) : Consumer<'T,'V> = upcast Windowed (windowSize, next) and [] SeqComponent<'T,'U> (next:ICompletionChaining) = inherit Consumer<'T,'U>() @@ -972,6 +977,34 @@ namespace Microsoft.FSharp.Collections outOfBand.StopFurtherProcessing pipeIdx false + and Windowed<'T,'V> (windowSize: int, next:Consumer<'T[],'V>) = + inherit SeqComponent<'T,'V>(next) + + let arr = Array.zeroCreateUnchecked windowSize + let r = ref (windowSize - 1) + let i = ref 0 + + let arrWindow innerDerefI j = arr.[(innerDerefI+j) % windowSize] + + override __.ProcessNext (input:'T) : bool = + let derefI = !i + arr.[derefI] <- input + i := (derefI + 1) % windowSize + let derefR = !r + if derefR = 0 then + let innerDerefI = !i + if windowSize < 32 then + let window = Array.init windowSize (arrWindow innerDerefI) + avoidTailCall (next.ProcessNext window) + else + let window = Array.zeroCreateUnchecked windowSize + Array.Copy(arr, innerDerefI, window, 0, windowSize - innerDerefI) + Array.Copy(arr, 0, window, windowSize - innerDerefI, innerDerefI) + avoidTailCall (next.ProcessNext window) + else + r := (derefR - 1) + false + type SeqProcessNextStates = | InProcess = 0 | NotStarted = 1 @@ -2203,7 +2236,7 @@ namespace Microsoft.FSharp.Collections let windowed windowSize (source: seq<_>) = if windowSize <= 0 then invalidArgFmt "windowSize" "{0}\nwindowSize = {1}" [|SR.GetString SR.inputMustBePositive; windowSize|] - source |> seqFactory (Composer.Seq.WindowedFactory (windowSize)) + source |> seqFactory (Composer.WindowedFactory (windowSize)) [] let cache (source : seq<'T>) = From ec3af9d7862dea2bdf8817baea45a28c656c1be0 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Tue, 1 Nov 2016 18:25:18 +1100 Subject: [PATCH 50/59] Tightening up Seq.windowed - removed ref vars, as can just us let mutable - renamed variables to more meaningful names - removed modulus because I can --- src/fsharp/FSharp.Core/seq.fs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index c688866dae6..e79b57a4ed8 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -980,30 +980,30 @@ namespace Microsoft.FSharp.Collections and Windowed<'T,'V> (windowSize: int, next:Consumer<'T[],'V>) = inherit SeqComponent<'T,'V>(next) - let arr = Array.zeroCreateUnchecked windowSize - let r = ref (windowSize - 1) - let i = ref 0 + let circularBuffer = Array.zeroCreateUnchecked windowSize + let mutable idx = 0 - let arrWindow innerDerefI j = arr.[(innerDerefI+j) % windowSize] + let mutable priming = windowSize - 1 override __.ProcessNext (input:'T) : bool = - let derefI = !i - arr.[derefI] <- input - i := (derefI + 1) % windowSize - let derefR = !r - if derefR = 0 then - let innerDerefI = !i + circularBuffer.[idx] <- input + + idx <- idx + 1 + if idx = windowSize then + idx <- 0 + + if priming > 0 then + priming <- priming - 1 + false + else if windowSize < 32 then - let window = Array.init windowSize (arrWindow innerDerefI) + let window = Array.init windowSize (fun i -> circularBuffer.[(idx+i) % windowSize]) avoidTailCall (next.ProcessNext window) else let window = Array.zeroCreateUnchecked windowSize - Array.Copy(arr, innerDerefI, window, 0, windowSize - innerDerefI) - Array.Copy(arr, 0, window, windowSize - innerDerefI, innerDerefI) + Array.Copy(circularBuffer, idx, window, 0, windowSize - idx) + Array.Copy(circularBuffer, 0, window, windowSize - idx, idx) avoidTailCall (next.ProcessNext window) - else - r := (derefR - 1) - false type SeqProcessNextStates = | InProcess = 0 From a038513a56e7a2305c9c55f2366349e821169c8f Mon Sep 17 00:00:00 2001 From: liboz Date: Thu, 3 Nov 2016 22:50:07 -0400 Subject: [PATCH 51/59] Reduce the diff on seq.fs so that it is easier to review on GitHub --- src/fsharp/FSharp.Core/seq.fs | 1830 +----------------------- src/fsharp/FSharp.Core/seq.fsi | 73 +- src/fsharp/FSharp.Core/seqcomposer.fs | 560 ++++---- src/fsharp/FSharp.Core/seqcomposer.fsi | 260 ++-- 4 files changed, 551 insertions(+), 2172 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index e79b57a4ed8..daafe8076c0 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -1,423 +1,5 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.FSharp.Collections - - open System - open System.Diagnostics - open System.Collections - open System.Collections.Generic - open Microsoft.FSharp.Core - open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators - open Microsoft.FSharp.Core.Operators - open Microsoft.FSharp.Control - open Microsoft.FSharp.Collections - - module IEnumerator = - - let noReset() = raise (new System.NotSupportedException(SR.GetString(SR.resetNotSupported))) - let notStarted() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationNotStarted))) - let alreadyFinished() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationAlreadyFinished))) - let check started = if not started then notStarted() - let dispose (r : System.IDisposable) = r.Dispose() - - let cast (e : IEnumerator) : IEnumerator<'T> = - { new IEnumerator<'T> with - member x.Current = unbox<'T> e.Current - interface IEnumerator with - member x.Current = unbox<'T> e.Current :> obj - member x.MoveNext() = e.MoveNext() - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = - match e with - | :? System.IDisposable as e -> e.Dispose() - | _ -> () } - - /// A concrete implementation of an enumerator that returns no values - [] - type EmptyEnumerator<'T>() = - let mutable started = false - interface IEnumerator<'T> with - member x.Current = - check started - (alreadyFinished() : 'T) - - interface System.Collections.IEnumerator with - member x.Current = - check started - (alreadyFinished() : obj) - member x.MoveNext() = - if not started then started <- true - false - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = () - - let Empty<'T> () = (new EmptyEnumerator<'T>() :> IEnumerator<'T>) - - let rec tryItem index (e : IEnumerator<'T>) = - if not (e.MoveNext()) then None - elif index = 0 then Some(e.Current) - else tryItem (index-1) e - - let rec nth index (e : IEnumerator<'T>) = - if not (e.MoveNext()) then - let shortBy = index + 1 - invalidArgFmt "index" - "{0}\nseq was short by {1} {2}" - [|SR.GetString SR.notEnoughElements; shortBy; (if shortBy = 1 then "element" else "elements")|] - if index = 0 then e.Current - else nth (index-1) e - - let readAndClear r = - lock r (fun () -> match !r with None -> None | Some _ as res -> r := None; res) - - let generateWhileSome openf compute closef : IEnumerator<'U> = - let started = ref false - let curr = ref None - let state = ref (Some(openf())) - let getCurr() = - check !started - match !curr with None -> alreadyFinished() | Some x -> x - let start() = if not !started then (started := true) - - let dispose() = readAndClear state |> Option.iter closef - let finish() = (try dispose() finally curr := None) - { new IEnumerator<'U> with - member x.Current = getCurr() - interface IEnumerator with - member x.Current = box (getCurr()) - member x.MoveNext() = - start() - match !state with - | None -> false (* we started, then reached the end, then got another MoveNext *) - | Some s -> - match (try compute s with e -> finish(); reraise()) with - | None -> finish(); false - | Some _ as x -> curr := x; true - - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = dispose() } - - [] - type Singleton<'T>(v:'T) = - let mutable started = false - interface IEnumerator<'T> with - member x.Current = v - interface IEnumerator with - member x.Current = box v - member x.MoveNext() = if started then false else (started <- true; true) - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = () - - let Singleton x = (new Singleton<'T>(x) :> IEnumerator<'T>) - - let EnumerateThenFinally f (e : IEnumerator<'T>) = - { new IEnumerator<'T> with - member x.Current = e.Current - interface IEnumerator with - member x.Current = (e :> IEnumerator).Current - member x.MoveNext() = e.MoveNext() - member x.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = - try - e.Dispose() - finally - f() - } - - -namespace Microsoft.FSharp.Core.CompilerServices - - open System - open System.Diagnostics - open Microsoft.FSharp.Core - open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators - open Microsoft.FSharp.Core.Operators - open Microsoft.FSharp.Control - open Microsoft.FSharp.Collections - open Microsoft.FSharp.Primitives.Basics - open System.Collections - open System.Collections.Generic - - module RuntimeHelpers = - - [] - type internal StructBox<'T when 'T : equality>(value:'T) = - member x.Value = value - static member Comparer = - let gcomparer = HashIdentity.Structural<'T> - { new IEqualityComparer> with - member __.GetHashCode(v) = gcomparer.GetHashCode(v.Value) - member __.Equals(v1,v2) = gcomparer.Equals(v1.Value,v2.Value) } - - let inline checkNonNull argName arg = - match box arg with - | null -> nullArg argName - | _ -> () - - let mkSeq f = - { new IEnumerable<'U> with - member x.GetEnumerator() = f() - interface IEnumerable with - member x.GetEnumerator() = (f() :> IEnumerator) } - - [] - type EmptyEnumerable<'T> = - | EmptyEnumerable - interface IEnumerable<'T> with - member x.GetEnumerator() = IEnumerator.Empty<'T>() - interface IEnumerable with - member x.GetEnumerator() = (IEnumerator.Empty<'T>() :> IEnumerator) - - let Generate openf compute closef = - mkSeq (fun () -> IEnumerator.generateWhileSome openf compute closef) - - let GenerateUsing (openf : unit -> ('U :> System.IDisposable)) compute = - Generate openf compute (fun (s:'U) -> s.Dispose()) - - let EnumerateFromFunctions opener moveNext current = - Generate - opener - (fun x -> if moveNext x then Some(current x) else None) - (fun x -> match box(x) with :? System.IDisposable as id -> id.Dispose() | _ -> ()) - - // A family of enumerators that can have additional 'finally' actions added to the enumerator through - // the use of mutation. This is used to 'push' the disposal action for a 'use' into the next enumerator. - // For example, - // seq { use x = ... - // while ... } - // results in the 'while' loop giving an adjustable enumerator. This is then adjusted by adding the disposal action - // from the 'use' into the enumerator. This means that we avoid constructing a two-deep enumerator chain in this - // common case. - type IFinallyEnumerator = - abstract AppendFinallyAction : (unit -> unit) -> unit - - /// A concrete implementation of IEnumerable that adds the given compensation to the "Dispose" chain of any - /// enumerators returned by the enumerable. - [] - type FinallyEnumerable<'T>(compensation: unit -> unit, restf: unit -> seq<'T>) = - interface IEnumerable<'T> with - member x.GetEnumerator() = - try - let ie = restf().GetEnumerator() - match ie with - | :? IFinallyEnumerator as a -> - a.AppendFinallyAction(compensation) - ie - | _ -> - IEnumerator.EnumerateThenFinally compensation ie - with e -> - compensation() - reraise() - interface IEnumerable with - member x.GetEnumerator() = ((x :> IEnumerable<'T>).GetEnumerator() :> IEnumerator) - - /// An optimized object for concatenating a sequence of enumerables - [] - type ConcatEnumerator<'T,'U when 'U :> seq<'T>>(sources: seq<'U>) = - let mutable outerEnum = sources.GetEnumerator() - let mutable currInnerEnum = IEnumerator.Empty() - - let mutable started = false - let mutable finished = false - let mutable compensations = [] - - [] // false = unchecked - val mutable private currElement : 'T - - member x.Finish() = - finished <- true - try - match currInnerEnum with - | null -> () - | _ -> - try - currInnerEnum.Dispose() - finally - currInnerEnum <- null - finally - try - match outerEnum with - | null -> () - | _ -> - try - outerEnum.Dispose() - finally - outerEnum <- null - finally - let rec iter comps = - match comps with - | [] -> () - | h::t -> - try h() finally iter t - try - compensations |> List.rev |> iter - finally - compensations <- [] - - member x.GetCurrent() = - IEnumerator.check started - if finished then IEnumerator.alreadyFinished() else x.currElement - - interface IFinallyEnumerator with - member x.AppendFinallyAction(f) = - compensations <- f :: compensations - - interface IEnumerator<'T> with - member x.Current = x.GetCurrent() - - interface IEnumerator with - member x.Current = box (x.GetCurrent()) - - member x.MoveNext() = - if not started then (started <- true) - if finished then false - else - let rec takeInner () = - // check the inner list - if currInnerEnum.MoveNext() then - x.currElement <- currInnerEnum.Current - true - else - // check the outer list - let rec takeOuter() = - if outerEnum.MoveNext() then - let ie = outerEnum.Current - // Optimization to detect the statically-allocated empty IEnumerables - match box ie with - | :? EmptyEnumerable<'T> -> - // This one is empty, just skip, don't call GetEnumerator, try again - takeOuter() - | _ -> - // OK, this one may not be empty. - // Don't forget to dispose of the enumerator for the inner list now we're done with it - currInnerEnum.Dispose() - currInnerEnum <- ie.GetEnumerator() - takeInner () - else - // We're done - x.Finish() - false - takeOuter() - takeInner () - - member x.Reset() = IEnumerator.noReset() - - interface System.IDisposable with - member x.Dispose() = - if not finished then - x.Finish() - - let EnumerateUsing (resource : 'T :> System.IDisposable) (rest: 'T -> #seq<'U>) = - (FinallyEnumerable((fun () -> match box resource with null -> () | _ -> resource.Dispose()), - (fun () -> rest resource :> seq<_>)) :> seq<_>) - - let mkConcatSeq (sources: seq<'U :> seq<'T>>) = - mkSeq (fun () -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>) - - let EnumerateWhile (g : unit -> bool) (b: seq<'T>) : seq<'T> = - let started = ref false - let curr = ref None - let getCurr() = - IEnumerator.check !started - match !curr with None -> IEnumerator.alreadyFinished() | Some x -> x - let start() = if not !started then (started := true) - - let finish() = (curr := None) - mkConcatSeq - (mkSeq (fun () -> - { new IEnumerator<_> with - member x.Current = getCurr() - interface IEnumerator with - member x.Current = box (getCurr()) - member x.MoveNext() = - start() - let keepGoing = (try g() with e -> finish (); reraise ()) in - if keepGoing then - curr := Some(b); true - else - finish(); false - member x.Reset() = IEnumerator.noReset() - interface System.IDisposable with - member x.Dispose() = () })) - - let EnumerateThenFinally (rest : seq<'T>) (compensation : unit -> unit) = - (FinallyEnumerable(compensation, (fun () -> rest)) :> seq<_>) - - let CreateEvent (add : 'Delegate -> unit) (remove : 'Delegate -> unit) (create : (obj -> 'Args -> unit) -> 'Delegate ) :IEvent<'Delegate,'Args> = - // Note, we implement each interface explicitly: this works around a bug in the CLR - // implementation on CompactFramework 3.7, used on Windows Phone 7 - { new obj() with - member x.ToString() = "" - interface IEvent<'Delegate,'Args> - interface IDelegateEvent<'Delegate> with - member x.AddHandler(h) = add h - member x.RemoveHandler(h) = remove h - interface System.IObservable<'Args> with - member x.Subscribe(r:IObserver<'Args>) = - let h = create (fun _ args -> r.OnNext(args)) - add h - { new System.IDisposable with - member x.Dispose() = remove h } } - - - [] - type GeneratedSequenceBase<'T>() = - let mutable redirectTo : GeneratedSequenceBase<'T> = Unchecked.defaultof<_> - let mutable redirect : bool = false - - abstract GetFreshEnumerator : unit -> IEnumerator<'T> - abstract GenerateNext : next:byref> -> int // 0 = Stop, 1 = Yield, 2 = Goto - abstract Close: unit -> unit - abstract CheckClose: bool - abstract LastGenerated : 'T - - //[] - member x.MoveNextImpl() = - let active = - if redirect then redirectTo - else x - let mutable target = null - match active.GenerateNext(&target) with - | 1 -> - true - | 2 -> - match target.GetEnumerator() with - | :? GeneratedSequenceBase<'T> as g when not active.CheckClose -> - redirectTo <- g - | e -> - redirectTo <- - { new GeneratedSequenceBase<'T>() with - member x.GetFreshEnumerator() = e - member x.GenerateNext(_) = if e.MoveNext() then 1 else 0 - member x.Close() = try e.Dispose() finally active.Close() - member x.CheckClose = true - member x.LastGenerated = e.Current } - redirect <- true - x.MoveNextImpl() - | _ (* 0 *) -> - false - - interface IEnumerable<'T> with - member x.GetEnumerator() = x.GetFreshEnumerator() - interface IEnumerable with - member x.GetEnumerator() = (x.GetFreshEnumerator() :> IEnumerator) - interface IEnumerator<'T> with - member x.Current = if redirect then redirectTo.LastGenerated else x.LastGenerated - member x.Dispose() = if redirect then redirectTo.Close() else x.Close() - interface IEnumerator with - member x.Current = box (if redirect then redirectTo.LastGenerated else x.LastGenerated) - - //[] - member x.MoveNext() = x.MoveNextImpl() - - member x.Reset() = raise <| new System.NotSupportedException() - - namespace Microsoft.FSharp.Collections open System @@ -453,1290 +35,20 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = - module Composer = - open IEnumerator - - module Internal = - type PipeIdx = int - type ``PipeIdx?`` = Nullable - let emptyPipeIdx = Nullable () - let inline getPipeIdx (maybePipeIdx:``PipeIdx?``) = if maybePipeIdx.HasValue then maybePipeIdx.Value else 1 - let inline makePipeIdx (pipeIdx:PipeIdx) = Nullable pipeIdx - - type ICompletionChaining = - abstract OnComplete : PipeIdx -> unit - abstract OnDispose : unit -> unit - - type IOutOfBand = - abstract StopFurtherProcessing : PipeIdx -> unit - - [] - type Consumer<'T,'U> () = - abstract ProcessNext : input:'T -> bool - - abstract OnComplete : PipeIdx -> unit - abstract OnDispose : unit -> unit - - default __.OnComplete _ = () - default __.OnDispose () = () - - interface ICompletionChaining with - member this.OnComplete terminatingIdx = - this.OnComplete terminatingIdx - - member this.OnDispose () = - try this.OnDispose () - finally () - - [] - type Values<'a,'b> = - val mutable _1 : 'a - val mutable _2 : 'b - - new (a:'a, b: 'b) = { - _1 = a - _2 = b - } - - [] - type Values<'a,'b,'c> = - val mutable _1 : 'a - val mutable _2 : 'b - val mutable _3 : 'c - - new (a:'a, b:'b, c:'c) = { - _1 = a - _2 = b - _3 = c - } - - [] - type Folder<'T, 'U> = - inherit Consumer<'T,'T> - - val mutable Value : 'U - - new (init) = { - inherit Consumer<'T,'T>() - Value = init - } - - type ISeqFactory<'T,'U> = - abstract PipeIdx : PipeIdx - abstract Create<'V> : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> - - type ISeq<'T> = - inherit IEnumerable<'T> - abstract member Compose<'U> : (ISeqFactory<'T,'U>) -> ISeq<'U> - abstract member ForEach<'consumer when 'consumer :> Consumer<'T,'T>> : f:((unit->unit)->'consumer) -> 'consumer - - open Internal - - module Helpers = - // used for performance reasons; these are not recursive calls, so should be safe - // ** it should be noted that potential changes to the f# compiler may render this function - // ineffictive ** - let inline avoidTailCall boolean = match boolean with true -> true | false -> false - - // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality - // is fixed with the compiler then these functions can be removed. - let inline upcastSeq (t:#ISeq<'T>) : ISeq<'T> = (# "" t : ISeq<'T> #) - let inline upcastFactory (t:#ISeqFactory<'T,'U>) : ISeqFactory<'T,'U> = (# "" t : ISeqFactory<'T,'U> #) - let inline upcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) - let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) - let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) - let inline upcastICompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) - - open Helpers - - type [] SeqComponentFactory<'T,'U> (pipeIdx:``PipeIdx?``) = - new() = SeqComponentFactory<'T,'U> (emptyPipeIdx) - - interface ISeqFactory<'T,'U> with - member __.PipeIdx = getPipeIdx pipeIdx - member __.Create<'V> (_:IOutOfBand) (_:``PipeIdx?``) (_:Consumer<'U,'V>) : Consumer<'T,'V> = failwith "library implementation error: Create on base factory should not be called" - - and ComposedFactory<'T,'U,'V> private (first:ISeqFactory<'T,'U>, second:ISeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = - inherit SeqComponentFactory<'T,'V> (makePipeIdx secondPipeIdx) - - interface ISeqFactory<'T,'V> with - member this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'V,'W>) : Consumer<'T,'W> = - first.Create outOfBand pipeIdx (second.Create outOfBand (makePipeIdx secondPipeIdx) next) - - static member Combine (first:ISeqFactory<'T,'U>) (second:ISeqFactory<'U,'V>) : ISeqFactory<'T,'V> = - ComposedFactory(first, second, first.PipeIdx+1) |> upcastFactory - - and ChooseFactory<'T,'U> (filter:'T->option<'U>) = - inherit SeqComponentFactory<'T,'U> () - interface ISeqFactory<'T,'U> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) - - and DistinctFactory<'T when 'T: equality> () = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) - - and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) - - and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) - - and FilterFactory<'T> (filter:'T->bool) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = - match next with - | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter - | _ -> upcast Filter (filter, next) - - and IdentityFactory<'T> () = - inherit SeqComponentFactory<'T,'T> () - static let singleton = IdentityFactory<'T>() - interface ISeqFactory<'T,'T> with - member __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next - static member Instance = singleton - - and MapFactory<'T,'U> (map:'T->'U) = - inherit SeqComponentFactory<'T,'U> () - interface ISeqFactory<'T,'U> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = - match next with - | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map - | _ -> upcast Map<_,_,_> (map, next) - - and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = - inherit SeqComponentFactory<'First,'U> () - interface ISeqFactory<'First,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, outOfBand, next, getPipeIdx pipeIdx) - - and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = - inherit SeqComponentFactory<'Second,'U> () - interface ISeqFactory<'Second,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, outOfBand, next, getPipeIdx pipeIdx) - - and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = - inherit SeqComponentFactory<'First,'U> () - interface ISeqFactory<'First,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, outOfBand, next, getPipeIdx pipeIdx) - - and MapiFactory<'T,'U> (mapi:int->'T->'U) = - inherit SeqComponentFactory<'T,'U> () - interface ISeqFactory<'T,'U> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Mapi (mapi, next) - - and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = - inherit SeqComponentFactory<'First,'U> () - interface ISeqFactory<'First,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, outOfBand, next, getPipeIdx pipeIdx) - - and PairwiseFactory<'T> () = - inherit SeqComponentFactory<'T,'T*'T> () - interface ISeqFactory<'T,'T*'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) - - and ScanFactory<'T,'State> (folder:'State->'T->'State, initialState:'State) = - inherit SeqComponentFactory<'T,'State> () - interface ISeqFactory<'T,'State> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) - - and SkipFactory<'T> (count:int) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, next) - - and SkipWhileFactory<'T> (predicate:'T->bool) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) - - and TakeWhileFactory<'T> (predicate:'T->bool) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, outOfBand, next, getPipeIdx pipeIdx) - - and TakeFactory<'T> (count:int) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, outOfBand, next, getPipeIdx pipeIdx) - - and TailFactory<'T> () = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) - - and TruncateFactory<'T> (count:int) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, getPipeIdx pipeIdx) - - and WindowedFactory<'T> (windowSize:int) = - inherit SeqComponentFactory<'T, 'T[]> () - interface ISeqFactory<'T, 'T[]> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T[],'V>) : Consumer<'T,'V> = upcast Windowed (windowSize, next) - - and [] SeqComponent<'T,'U> (next:ICompletionChaining) = - inherit Consumer<'T,'U>() - - // Seq.init(Infinite)? lazily uses Current. The only Composer component that can do that is Skip - // and it can only do it at the start of a sequence - abstract Skipping : unit -> bool - - abstract CreateMap<'S> : map:('S->'T) -> SeqComponent<'S,'U> - abstract CreateFilter : filter:('T->bool) -> SeqComponent<'T,'U> - - interface ICompletionChaining with - member this.OnComplete terminatingIdx = - this.OnComplete terminatingIdx - next.OnComplete terminatingIdx - member this.OnDispose () = - try this.OnDispose () - finally next.OnDispose () - - default __.Skipping () = false - - default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) - default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) - - and Choose<'T,'U,'V> (choose:'T->option<'U>, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - match choose input with - | Some value -> avoidTailCall (next.ProcessNext value) - | None -> false - - and Distinct<'T,'V when 'T: equality> (next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) - - override __.ProcessNext (input:'T) : bool = - if hashSet.Add input then - avoidTailCall (next.ProcessNext input) - else - false - - and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) - - override __.ProcessNext (input:'T) : bool = - if hashSet.Add(keyFunction input) then - avoidTailCall (next.ProcessNext input) - else - false - - and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) - - override __.ProcessNext (input:'T) : bool = - if cached.Value.Add input then - avoidTailCall (next.ProcessNext input) - else - false - - and Filter<'T,'V> (filter:'T->bool, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) - - override __.ProcessNext (input:'T) : bool = - if filter input then - avoidTailCall (next.ProcessNext input) - else - false - - and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - if filter input then - avoidTailCall (next.ProcessNext (map input)) - else - false - - and Map<'T,'U,'V> (map:'T->'U, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) - - override __.ProcessNext (input:'T) : bool = - avoidTailCall (next.ProcessNext (map input)) - - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(next) - - let input2 = enumerable2.GetEnumerator () - let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map - - override __.ProcessNext (input:'First) : bool = - if input2.MoveNext () then - avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - override __.OnDispose () = - input2.Dispose () - - and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'Second,'V>(next) - - let input1 = enumerable1.GetEnumerator () - let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map - - override __.ProcessNext (input:'Second) : bool = - if input1.MoveNext () then - avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - override __.OnDispose () = - input1.Dispose () - - and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(next) - - let input2 = enumerable2.GetEnumerator () - let input3 = enumerable3.GetEnumerator () - let map' = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt map - - override __.ProcessNext (input:'First) : bool = - if input2.MoveNext () && input3.MoveNext () then - avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - override __.OnDispose () = - try input2.Dispose () - finally input3.Dispose () - - and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - let u = map input - if filter u then - avoidTailCall (next.ProcessNext u) - else - false - - and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable idx = 0 - let mapi' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt mapi - - override __.ProcessNext (input:'T) : bool = - idx <- idx + 1 - avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) - - and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(next) - - let mutable idx = 0 - let input2 = enumerable2.GetEnumerator () - let mapi2' = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt map - - override __.ProcessNext (input:'First) : bool = - if input2.MoveNext () then - idx <- idx + 1 - avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - override __.OnDispose () = - input2.Dispose () - - and Pairwise<'T,'V> (next:Consumer<'T*'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable isFirst = true - let mutable lastValue = Unchecked.defaultof<'T> - - override __.ProcessNext (input:'T) : bool = - if isFirst then - lastValue <- input - isFirst <- false - false - else - let currentPair = lastValue, input - lastValue <- input - avoidTailCall (next.ProcessNext currentPair) - - and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:Consumer<'State,'V>) = - inherit SeqComponent<'T,'V>(next) - - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - let mutable foldResult = initialState - - override __.ProcessNext (input:'T) : bool = - foldResult <- f.Invoke(foldResult, input) - avoidTailCall (next.ProcessNext foldResult) - - and Skip<'T,'V> (skipCount:int, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable count = 0 - - override __.Skipping () = - if count < skipCount then - count <- count + 1 - true - else - false - - override __.ProcessNext (input:'T) : bool = - if count < skipCount then - count <- count + 1 - false - else - avoidTailCall (next.ProcessNext input) - - override __.OnComplete _ = - if count < skipCount then - let x = skipCount - count - invalidOpFmt "tried to skip {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - - and SkipWhile<'T,'V> (predicate:'T->bool, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable skip = true - - override __.ProcessNext (input:'T) : bool = - if skip then - skip <- predicate input - if skip then - false - else - avoidTailCall (next.ProcessNext input) - else - avoidTailCall (next.ProcessNext input) - - and Take<'T,'V> (takeCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipelineIdx:int) = - inherit Truncate<'T, 'V>(takeCount, outOfBand, next, pipelineIdx) - - override this.OnComplete terminatingIdx = - if terminatingIdx < pipelineIdx && this.Count < takeCount then - let x = takeCount - this.Count - invalidOpFmt "tried to take {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - - and TakeWhile<'T,'V> (predicate:'T->bool, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - if predicate input then - avoidTailCall (next.ProcessNext input) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - and Tail<'T, 'V> (next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable first = true - - override __.ProcessNext (input:'T) : bool = - if first then - first <- false - false - else - avoidTailCall (next.ProcessNext input) - - override this.OnComplete _ = - if first then - invalidArg "source" (SR.GetString(SR.notEnoughElements)) - - and Truncate<'T,'V> (truncateCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = - inherit SeqComponent<'T,'V>(next) - - let mutable count = 0 - - member __.Count = count - - override __.ProcessNext (input:'T) : bool = - if count < truncateCount then - count <- count + 1 - if count = truncateCount then - outOfBand.StopFurtherProcessing pipeIdx - avoidTailCall (next.ProcessNext input) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - and Windowed<'T,'V> (windowSize: int, next:Consumer<'T[],'V>) = - inherit SeqComponent<'T,'V>(next) - - let circularBuffer = Array.zeroCreateUnchecked windowSize - let mutable idx = 0 - - let mutable priming = windowSize - 1 - - override __.ProcessNext (input:'T) : bool = - circularBuffer.[idx] <- input - - idx <- idx + 1 - if idx = windowSize then - idx <- 0 - - if priming > 0 then - priming <- priming - 1 - false - else - if windowSize < 32 then - let window = Array.init windowSize (fun i -> circularBuffer.[(idx+i) % windowSize]) - avoidTailCall (next.ProcessNext window) - else - let window = Array.zeroCreateUnchecked windowSize - Array.Copy(circularBuffer, idx, window, 0, windowSize - idx) - Array.Copy(circularBuffer, 0, window, windowSize - idx, idx) - avoidTailCall (next.ProcessNext window) - - type SeqProcessNextStates = - | InProcess = 0 - | NotStarted = 1 - | Finished = 2 - - type Result<'T>() = - let mutable haltedIdx = 0 - - member val Current = Unchecked.defaultof<'T> with get, set - member val SeqState = SeqProcessNextStates.NotStarted with get, set - member __.HaltedIdx = haltedIdx - - interface IOutOfBand with - member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx - - // SetResult<> is used at the end of the chain of SeqComponents to assign the final value - type SetResult<'T> (result:Result<'T>) = - inherit Consumer<'T,'T>() - - override __.ProcessNext (input:'T) : bool = - result.Current <- input - true - - type OutOfBand() = - let mutable haltedIdx = 0 - interface IOutOfBand with member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx - member __.HaltedIdx = haltedIdx - - module ForEach = - let enumerable (enumerable:IEnumerable<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - use enumerator = enumerable.GetEnumerator () - while (outOfBand.HaltedIdx = 0) && (enumerator.MoveNext ()) do - consumer.ProcessNext enumerator.Current |> ignore - - let array (array:array<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let mutable idx = 0 - while (outOfBand.HaltedIdx = 0) && (idx < array.Length) do - consumer.ProcessNext array.[idx] |> ignore - idx <- idx + 1 - - let list (alist:list<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let rec iterate lst = - match outOfBand.HaltedIdx, lst with - | 0, hd :: tl -> - consumer.ProcessNext hd |> ignore - iterate tl - | _ -> () - iterate alist - - let unfold (generator:'S->option<'T*'S>) state (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let rec iterate current = - match outOfBand.HaltedIdx, generator current with - | 0, Some (item, next) -> - consumer.ProcessNext item |> ignore - iterate next - | _ -> () - - iterate state - - let makeIsSkipping (consumer:Consumer<'T,'U>) = - match consumer with - | :? SeqComponent<'T,'U> as c -> c.Skipping - | _ -> fun () -> false - - let init f (terminatingIdx:int) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let mutable idx = -1 - let isSkipping = makeIsSkipping consumer - let mutable maybeSkipping = true - while (outOfBand.HaltedIdx = 0) && (idx < terminatingIdx) do - if maybeSkipping then - maybeSkipping <- isSkipping () - - if (not maybeSkipping) then - consumer.ProcessNext (f (idx+1)) |> ignore - - idx <- idx + 1 - - let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:ISeqFactory<'T,'U>) executeOn = - let pipeline = OutOfBand() - let result = f (fun () -> (pipeline:>IOutOfBand).StopFurtherProcessing (current.PipeIdx+1)) - let consumer = current.Create pipeline emptyPipeIdx result - try - executeOn pipeline consumer - (upcastICompletionChaining consumer).OnComplete pipeline.HaltedIdx - result - finally - (upcastICompletionChaining consumer).OnDispose () - - module Enumerable = - type Empty<'T>() = - let current () = failwith "library implementation error: Current should never be called" - interface IEnumerator<'T> with - member __.Current = current () - interface IEnumerator with - member __.Current = current () - member __.MoveNext () = false - member __.Reset (): unit = noReset () - interface IDisposable with - member __.Dispose () = () - - type EmptyEnumerators<'T>() = - static let element : IEnumerator<'T> = upcast (new Empty<'T> ()) - static member Element = element - - [] - type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ICompletionChaining) = - interface IDisposable with - member __.Dispose() : unit = - seqComponent.OnDispose () - - interface IEnumerator with - member this.Current : obj = box ((upcastEnumerator this)).Current - member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)" - member __.Reset () : unit = noReset () - - interface IEnumerator<'T> with - member __.Current = - if result.SeqState = SeqProcessNextStates.InProcess then result.Current - else - match result.SeqState with - | SeqProcessNextStates.NotStarted -> notStarted() - | SeqProcessNextStates.Finished -> alreadyFinished() - | _ -> failwith "library implementation error: all states should have been handled" - - and [] EnumerableBase<'T> () = - let derivedClassShouldImplement () = - failwith "library implementation error: derived class should implement (should be abstract)" - - abstract member Append<'T> : (seq<'T>) -> IEnumerable<'T> - - default this.Append source = upcastEnumerable (AppendEnumerable [this; source]) - - interface IEnumerable with - member this.GetEnumerator () : IEnumerator = - let genericEnumerable = upcastEnumerable this - let genericEnumerator = genericEnumerable.GetEnumerator () - upcastEnumeratorNonGeneric genericEnumerator - - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement () - - interface ISeq<'T> with - member __.Compose _ = derivedClassShouldImplement () - member __.ForEach _ = derivedClassShouldImplement () - - and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit EnumeratorBase<'U>(result, seqComponent) - - let rec moveNext () = - if (result.HaltedIdx = 0) && source.MoveNext () then - if seqComponent.ProcessNext source.Current then - true - else - moveNext () - else - result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx - false - - interface IEnumerator with - member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess - moveNext () - - interface IDisposable with - member __.Dispose() = - try - source.Dispose () - finally - (upcastICompletionChaining seqComponent).OnDispose () - - and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:ISeqFactory<'T,'U>) = - inherit EnumerableBase<'U>() - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) - - interface ISeq<'U> with - member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.enumerable enumerable) - - and ConcatEnumerator<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = - let mutable state = SeqProcessNextStates.NotStarted - let main = sources.GetEnumerator () - - let mutable active = EmptyEnumerators.Element - - let rec moveNext () = - if active.MoveNext () then - true - elif main.MoveNext () then - active.Dispose () - active <- main.Current.GetEnumerator () - moveNext () - else - state <- SeqProcessNextStates.Finished - false - - interface IEnumerator<'T> with - member __.Current = - if state = SeqProcessNextStates.InProcess then active.Current - else - match state with - | SeqProcessNextStates.NotStarted -> notStarted() - | SeqProcessNextStates.Finished -> alreadyFinished() - | _ -> failwith "library implementation error: all states should have been handled" - - interface IEnumerator with - member this.Current = box ((upcastEnumerator this)).Current - member __.MoveNext () = - state <- SeqProcessNextStates.InProcess - moveNext () - member __.Reset () = noReset () - - interface IDisposable with - member __.Dispose() = - main.Dispose () - active.Dispose () - - and AppendEnumerable<'T> (sources:list>) = - inherit EnumerableBase<'T>() - - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = - upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) - - override this.Append source = - upcastEnumerable (AppendEnumerable (source :: sources)) - - interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable<'T,'V>(this, next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) - - and ConcatEnumerable<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = - inherit EnumerableBase<'T>() - - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = - upcastEnumerator (new ConcatEnumerator<_,_> (sources)) - - interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable<'T,'V>(this, next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) - - let create enumerable current = - upcastSeq (Enumerable(enumerable, current)) - - module EmptyEnumerable = - type Enumerable<'T> () = - inherit Enumerable.EnumerableBase<'T>() - - static let singleton = Enumerable<'T>() :> ISeq<'T> - static member Instance = singleton - - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>() - - override this.Append source = - upcastEnumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) - - interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable.Enumerable<'T,'V>(this, next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) - - - - module Array = - type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) - - let mutable idx = 0 - let mutable array = Unchecked.defaultof<_> - - let mutable initMoveNext = Unchecked.defaultof<_> - do - initMoveNext <- - fun () -> - result.SeqState <- SeqProcessNextStates.InProcess - array <- delayedArray () - initMoveNext <- ignore - - let rec moveNext () = - if (result.HaltedIdx = 0) && idx < array.Length then - idx <- idx+1 - if seqComponent.ProcessNext array.[idx-1] then - true - else - moveNext () - else - result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx - false - - interface IEnumerator with - member __.MoveNext () = - initMoveNext () - moveNext () - - type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:ISeqFactory<'T,'U>) = - inherit Enumerable.EnumerableBase<'U>() - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - - interface ISeq<'U> with - member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.array (delayedArray ())) - - let createDelayed (delayedArray:unit->array<'T>) (current:ISeqFactory<'T,'U>) = - upcastSeq (Enumerable(delayedArray, current)) - - let create (array:array<'T>) (current:ISeqFactory<'T,'U>) = - createDelayed (fun () -> array) current - - let createDelayedId (delayedArray:unit -> array<'T>) = - createDelayed delayedArray IdentityFactory.Instance - - let createId (array:array<'T>) = - create array IdentityFactory.Instance - - module List = - type Enumerator<'T,'U>(alist:list<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) - - let mutable list = alist - - let rec moveNext current = - match result.HaltedIdx, current with - | 0, head::tail -> - if seqComponent.ProcessNext head then - list <- tail - true - else - moveNext tail - | _ -> - result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx - false - - interface IEnumerator with - member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess - moveNext list - - type Enumerable<'T,'U>(alist:list<'T>, current:ISeqFactory<'T,'U>) = - inherit Enumerable.EnumerableBase<'U>() - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - - interface ISeq<'U> with - member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.list alist) - - let create alist current = - upcastSeq (Enumerable(alist, current)) - - module Unfold = - type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) - - let mutable current = state - - let rec moveNext () = - match result.HaltedIdx, generator current with - | 0, Some (item, nextState) -> - current <- nextState - if seqComponent.ProcessNext item then - true - else - moveNext () - | _ -> false - - interface IEnumerator with - member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess - moveNext () - - type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:ISeqFactory<'T,'U>) = - inherit Enumerable.EnumerableBase<'U>() - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - - interface ISeq<'U> with - member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.unfold generator state) - - module Init = - // The original implementation of "init" delayed the calculation of Current, and so it was possible - // to do MoveNext without it's value being calculated. - // I can imagine only two scenerios where that is possibly sane, although a simple solution is readily - // at hand in both cases. The first is that of an expensive generator function, where you skip the - // first n elements. The simple solution would have just been to have a map ((+) n) as the first operation - // instead. The second case would be counting elements, but that is only of use if you're not filtering - // or mapping or doing anything else (as that would cause Current to be evaluated!) and - // so you already know what the count is!! Anyway, someone thought it was a good idea, so - // I have had to add an extra function that is used in Skip to determine if we are touching - // Current or not. - - let getTerminatingIdx (count:Nullable) = - // we are offset by 1 to allow for values going up to System.Int32.MaxValue - // System.Int32.MaxValue is an illegal value for the "infinite" sequence - if count.HasValue then - count.Value - 1 - else - System.Int32.MaxValue - - type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) - - let isSkipping = - ForEach.makeIsSkipping seqComponent - - let terminatingIdx = - getTerminatingIdx count - - let mutable maybeSkipping = true - let mutable idx = -1 - - let rec moveNext () = - if (result.HaltedIdx = 0) && idx < terminatingIdx then - idx <- idx + 1 - - if maybeSkipping then - // Skip can only is only checked at the start of the sequence, so once - // triggered, we stay triggered. - maybeSkipping <- isSkipping () - - if maybeSkipping then - moveNext () - elif seqComponent.ProcessNext (f idx) then - true - else - moveNext () - elif (result.HaltedIdx = 0) && idx = System.Int32.MaxValue then - raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) - else - result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx - false - - interface IEnumerator with - member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess - moveNext () - - type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:ISeqFactory<'T,'U>) = - inherit Enumerable.EnumerableBase<'U>() - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) - - interface ISeq<'U> with - member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) - - member this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = - let terminatingIdx = getTerminatingIdx count - ForEach.execute createResult current (ForEach.init f terminatingIdx) - - let upto lastOption f = - match lastOption with - | Some b when b<0 -> failwith "library implementation error: upto can never be called with a negative value" - | _ -> - let unstarted = -1 // index value means unstarted (and no valid index) - let completed = -2 // index value means completed (and no valid index) - let unreachable = -3 // index is unreachable from 0,1,2,3,... - let finalIndex = match lastOption with - | Some b -> b // here b>=0, a valid end value. - | None -> unreachable // run "forever", well as far as Int32.MaxValue since indexing with a bounded type. - // The Current value for a valid index is "f i". - // Lazy<_> values are used as caches, to store either the result or an exception if thrown. - // These "Lazy<_>" caches are created only on the first call to current and forced immediately. - // The lazy creation of the cache nodes means enumerations that skip many Current values are not delayed by GC. - // For example, the full enumeration of Seq.initInfinite in the tests. - // state - let index = ref unstarted - // a Lazy node to cache the result/exception - let current = ref (Unchecked.defaultof<_>) - let setIndex i = index := i; current := (Unchecked.defaultof<_>) // cache node unprimed, initialised on demand. - let getCurrent() = - if !index = unstarted then notStarted() - if !index = completed then alreadyFinished() - match box !current with - | null -> current := Lazy<_>.Create(fun () -> f !index) - | _ -> () - // forced or re-forced immediately. - (!current).Force() - { new IEnumerator<'U> with - member x.Current = getCurrent() - interface IEnumerator with - member x.Current = box (getCurrent()) - member x.MoveNext() = - if !index = completed then - false - elif !index = unstarted then - setIndex 0 - true - else ( - if !index = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) - if !index = finalIndex then - false - else - setIndex (!index + 1) - true - ) - member self.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = () } - - type EnumerableDecider<'T>(count:Nullable, f:int->'T) = - inherit Enumerable.EnumerableBase<'T>() - - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = - // we defer back to the original implementation as, as it's quite idiomatic in it's decision - // to calculate Current in a lazy fashion. I doubt anyone is really using this functionality - // in the way presented, but it's possible. - upto (if count.HasValue then Some (count.Value-1) else None) f - - interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable<'T,'V>(count, f, next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (upcastEnumerable this)) - - open RuntimeHelpers - - [] - let toComposer (source:seq<'T>) : ISeq<'T> = - checkNonNull "source" source - match source with - | :? ISeq<'T> as s -> s - | :? array<'T> as a -> upcastSeq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) - | :? list<'T> as a -> upcastSeq (List.Enumerable(a, IdentityFactory.Instance)) - | _ -> upcastSeq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) - - let inline foreach f (source:ISeq<_>) = - source.ForEach f - - let inline compose factory (source:ISeq<'T>) = - source.Compose factory - - [] - let empty<'T> = EmptyEnumerable.Enumerable<'T>.Instance - - [] - let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> = - upcastSeq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) - - [] - let initInfinite<'T> (f:int->'T) : ISeq<'T> = - upcastSeq (new Init.EnumerableDecider<'T>(Nullable (), f)) - - [] - let init<'T> (count:int) (f:int->'T) : ISeq<'T> = - if count < 0 then invalidArgInputMustBeNonNegative "count" count - elif count = 0 then empty else - upcastSeq (new Init.EnumerableDecider<'T>(Nullable count, f)) - - [] - let iter f (source:ISeq<'T>) = - source - |> foreach (fun _ -> - { new Consumer<'T,'T> () with - override this.ProcessNext value = - f value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> ignore - - [] - let tryItem i (source:ISeq<'T>) = - if i < 0 then None else - source - |> foreach (fun halt -> - { new Folder<'T, Values>> (Values<_,_> (0, None)) with - override this.ProcessNext value = - if this.Value._1 = i then - this.Value._2 <- Some value - halt () - else - this.Value._1 <- this.Value._1 + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun item -> item.Value._2 - - [] - let iteri f (source:ISeq<'T>) = - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f - - source - |> foreach (fun _ -> - { new Folder<'T, int> (0) with - override this.ProcessNext value = - f.Invoke(this.Value, value) - this.Value <- this.Value + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> ignore - - [] - let exists f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, bool> (false) with - override this.ProcessNext value = - if f value then - this.Value <- true - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun exists -> exists.Value - - [] - let inline contains element (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, bool> (false) with - override this.ProcessNext value = - if element = value then - this.Value <- true - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun contains -> contains.Value - - [] - let forall f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, bool> (true) with - override this.ProcessNext value = - if not (f value) then - this.Value <- false - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun forall -> forall.Value - - [] - let filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = - source - |> compose (FilterFactory f) - - [] - let map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = - source - |> compose (MapFactory f) - - [] - let mapi f source = - source - |> compose (MapiFactory f) - - [] - let choose f source = - source - |> compose (ChooseFactory f) - - [] - let indexed source = - source - |> compose (MapiFactory (fun i x -> i,x)) - - [] - let tryPick f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, Option<'U>> (None) with - override this.ProcessNext value = - match f value with - | (Some _) as some -> - this.Value <- some - halt () - | None -> () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun pick -> pick.Value - - [] - let tryFind f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, Option<'T>> (None) with - override this.ProcessNext value = - if f value then - this.Value <- Some value - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun find -> find.Value - - #if FX_NO_ICLONEABLE open Microsoft.FSharp.Core.ICloneableExtensions #else #endif + let mkDelayedSeq (f: unit -> IEnumerable<'T>) = mkSeq (fun () -> f().GetEnumerator()) let inline indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) [] - let toComposer (source:seq<'T>): Composer.Internal.ISeq<'T> = - Composer.toComposer source + let toComposer (source:seq<'T>): Composer.Core.ISeq<'T> = + Composer.Seq.toComposer source let inline foreach f (source:seq<_>) = - Composer.foreach f (toComposer source) + Composer.Seq.foreach f (toComposer source) let inline foreach f (source:seq<_>) = Composer.Seq.foreach f (toComposer source) @@ -1754,7 +66,7 @@ namespace Microsoft.FSharp.Collections [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> = - Composer.unfold generator state + Composer.Seq.unfold generator state |> Composer.Helpers.upcastEnumerable [] @@ -1762,17 +74,17 @@ namespace Microsoft.FSharp.Collections [] let initInfinite<'T> (f:int->'T) : IEnumerable<'T> = - Composer.initInfinite f + Composer.Seq.initInfinite f |> Composer.Helpers.upcastEnumerable [] let init<'T> (count:int) (f:int->'T) : IEnumerable<'T> = - Composer.init count f + Composer.Seq.init count f |> Composer.Helpers.upcastEnumerable [] let iter f (source : seq<'T>) = - Composer.iter f (toComposer source) + Composer.Seq.iter f (toComposer source) [] let tryHead (source : seq<_>) = @@ -1789,7 +101,7 @@ namespace Microsoft.FSharp.Collections if i < 0 then invalidArgInputMustBeNonNegative "index" i else source |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values<_,_,_> (0, false, Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values<_,_,_> (0, false, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 = i then this.Value._2 <- true @@ -1809,26 +121,26 @@ namespace Microsoft.FSharp.Collections [] let tryItem i (source:seq<'T>) = - Composer.tryItem i (toComposer source) + Composer.Seq.tryItem i (toComposer source) [] let nth i (source : seq<'T>) = item i source [] let iteri f (source:seq<'T>) = - Composer.iteri f (toComposer source) + Composer.Seq.iteri f (toComposer source) [] let exists f (source:seq<'T>) = - Composer.exists f (toComposer source) + Composer.Seq.exists f (toComposer source) [] let inline contains element (source:seq<'T>) = - Composer.contains element (toComposer source) + Composer.Seq.contains element (toComposer source) [] let forall f (source:seq<'T>) = - Composer.forall f (toComposer source) + Composer.Seq.forall f (toComposer source) [] let iter2 f (source1 : seq<_>) (source2 : seq<_>) = @@ -1839,7 +151,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<_,_> () with + { new Composer.Core.Folder<_,_> () with override this.ProcessNext value = if (e2.MoveNext()) then f.Invoke(value, e2.Current) @@ -1857,7 +169,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<_,int> (0) with + { new Composer.Core.Folder<_,int> (0) with override this.ProcessNext value = if (e2.MoveNext()) then f.Invoke(this.Value, value, e2.Current) @@ -1877,14 +189,14 @@ namespace Microsoft.FSharp.Collections let private seqFactory createSeqComponent (source:seq<'T>) = checkNonNull "source" source match source with - | :? Composer.Internal.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose createSeqComponent) - | :? array<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.Array.create a createSeqComponent) - | :? list<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.List.create a createSeqComponent) - | _ -> Composer.Helpers.upcastEnumerable (Composer.Enumerable.create source createSeqComponent) + | :? Composer.Core.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose createSeqComponent) + | :? array<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.Seq.Array.create a createSeqComponent) + | :? list<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.Seq.List.create a createSeqComponent) + | _ -> Composer.Helpers.upcastEnumerable (Composer.Seq.Enumerable.create source createSeqComponent) [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = - Composer.filter f (toComposer source) + Composer.Seq.filter f (toComposer source) |> Composer.Helpers.upcastEnumerable [] @@ -1892,40 +204,40 @@ namespace Microsoft.FSharp.Collections [] let map<'T,'U> (f:'T->'U) (source:seq<'T>) : seq<'U> = - Composer.map f (toComposer source) + Composer.Seq.map f (toComposer source) |> Composer.Helpers.upcastEnumerable [] let mapi f source = - Composer.mapi f (toComposer source) + Composer.Seq.mapi f (toComposer source) |> Composer.Helpers.upcastEnumerable [] let mapi2 f source1 source2 = checkNonNull "source2" source2 - source1 |> seqFactory (Composer.Mapi2Factory (f, source2)) + source1 |> seqFactory (Composer.Seq.Mapi2Factory (f, source2)) [] let map2<'T,'U,'V> (f:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = checkNonNull "source1" source1 match source1 with - | :? Composer.Internal.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose (Composer.Map2FirstFactory (f, source2))) - | _ -> source2 |> seqFactory (Composer.Map2SecondFactory (f, source1)) + | :? Composer.Core.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose (Composer.Seq.Map2FirstFactory (f, source2))) + | _ -> source2 |> seqFactory (Composer.Seq.Map2SecondFactory (f, source1)) [] let map3 f source1 source2 source3 = checkNonNull "source2" source2 checkNonNull "source3" source3 - source1 |> seqFactory (Composer.Map3Factory (f, source2, source3)) + source1 |> seqFactory (Composer.Seq.Map3Factory (f, source2, source3)) [] let choose f source = - Composer.choose f (toComposer source) + Composer.Seq.choose f (toComposer source) |> Composer.Helpers.upcastEnumerable [] let indexed source = - Composer.indexed (toComposer source) + Composer.Seq.indexed (toComposer source) |> Composer.Helpers.upcastEnumerable [] @@ -1943,7 +255,7 @@ namespace Microsoft.FSharp.Collections [] let tryPick f (source : seq<'T>) = - Composer.tryPick f (toComposer source) + Composer.Seq.tryPick f (toComposer source) [] let pick f source = @@ -1953,7 +265,7 @@ namespace Microsoft.FSharp.Collections [] let tryFind f (source : seq<'T>) = - Composer.tryFind f (toComposer source) + Composer.Seq.tryFind f (toComposer source) [] let find f source = @@ -1966,7 +278,7 @@ namespace Microsoft.FSharp.Collections if count < 0 then invalidArgInputMustBeNonNegative "count" count (* Note: don't create or dispose any IEnumerable if n = 0 *) if count = 0 then empty else - source |> seqFactory (Composer.TakeFactory count) + source |> seqFactory (Composer.Seq.TakeFactory count) [] let isEmpty (source : seq<'T>) = @@ -1982,7 +294,7 @@ namespace Microsoft.FSharp.Collections [] let concat (sources:seq<#seq<'T>>) : seq<'T> = checkNonNull "sources" sources - upcast Composer.Enumerable.ConcatEnumerable sources + upcast Composer.Seq.Enumerable.ConcatEnumerable sources [] let length (source : seq<'T>) = @@ -2004,7 +316,7 @@ namespace Microsoft.FSharp.Collections source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,'State> (x) with + { new Composer.Core.Folder<'T,'State> (x) with override this.ProcessNext value = this.Value <- f.Invoke (this.Value, value) Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) @@ -2027,7 +339,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<_,'State> (state) with + { new Composer.Core.Folder<_,'State> (state) with override this.ProcessNext value = if (e2.MoveNext()) then this.Value <- f.Invoke(this.Value, value, e2.Current) @@ -2042,7 +354,7 @@ namespace Microsoft.FSharp.Collections source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2072,8 +384,8 @@ namespace Microsoft.FSharp.Collections checkNonNull "source1" source1 checkNonNull "source2" source2 match source1 with - | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Append source2 - | _ -> Composer.Helpers.upcastEnumerable (new Composer.Enumerable.AppendEnumerable<_>([source2; source1])) + | :? Composer.Seq.Enumerable.EnumerableBase<'T> as s -> s.Append source2 + | _ -> Composer.Helpers.upcastEnumerable (new Composer.Seq.Enumerable.AppendEnumerable<_>([source2; source1])) [] @@ -2088,7 +400,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<'T,int> (0) with + { new Composer.Core.Folder<'T,int> (0) with override this.ProcessNext value = if not (e2.MoveNext()) then this.Value <- 1 @@ -2117,7 +429,7 @@ namespace Microsoft.FSharp.Collections [] let ofArray (source : 'T array) = checkNonNull "source" source - Composer.Helpers.upcastEnumerable (Composer.Array.createId source) + Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createId source) [] let toArray (source : seq<'T>) = @@ -2171,17 +483,17 @@ namespace Microsoft.FSharp.Collections [] let truncate n (source: seq<'T>) = if n <= 0 then empty else - source |> seqFactory (Composer.TruncateFactory n) + source |> seqFactory (Composer.Seq.TruncateFactory n) [] let pairwise<'T> (source:seq<'T>) : seq<'T*'T> = - source |> seqFactory (Composer.PairwiseFactory ()) + source |> seqFactory (Composer.Seq.PairwiseFactory ()) [] let scan<'T,'State> f (z:'State) (source : seq<'T>): seq<'State> = let first = [|z|] :> IEnumerable<'State> - let rest = source |> seqFactory (Composer.ScanFactory (f, z)) - upcast Composer.Enumerable.ConcatEnumerable [|first; rest;|] + let rest = source |> seqFactory (Composer.Seq.ScanFactory (f, z)) + upcast Composer.Seq.Enumerable.ConcatEnumerable [|first; rest;|] [] let tryFindBack f (source : seq<'T>) = @@ -2205,7 +517,7 @@ namespace Microsoft.FSharp.Collections let tryFindIndex p (source:seq<_>) = source |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values, int>> (Composer.Internal.Values<_,_>(None, 0)) with + { new Composer.Core.Folder<'T, Composer.Core.Values, int>> (Composer.Core.Values<_,_>(None, 0)) with override this.ProcessNext value = if p value then this.Value._1 <- Some(this.Value._2) @@ -2236,7 +548,7 @@ namespace Microsoft.FSharp.Collections let windowed windowSize (source: seq<_>) = if windowSize <= 0 then invalidArgFmt "windowSize" "{0}\nwindowSize = {1}" [|SR.GetString SR.inputMustBePositive; windowSize|] - source |> seqFactory (Composer.WindowedFactory (windowSize)) + source |> seqFactory (Composer.Seq.WindowedFactory (windowSize)) [] let cache (source : seq<'T>) = @@ -2354,11 +666,11 @@ namespace Microsoft.FSharp.Collections [] let distinct source = - source |> seqFactory (Composer.DistinctFactory ()) + source |> seqFactory (Composer.Seq.DistinctFactory ()) [] let distinctBy keyf source = - source |> seqFactory (Composer.DistinctByFactory keyf) + source |> seqFactory (Composer.Seq.DistinctByFactory keyf) [] let sortBy keyf source = @@ -2367,7 +679,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceBy keyf array array - Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedSort) + Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedSort) [] let sort source = @@ -2376,7 +688,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlace array array - Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedSort) + Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedSort) [] let sortWith f source = @@ -2385,7 +697,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceWith f array array - Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedSort) + Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedSort) [] let inline sortByDescending keyf source = @@ -2436,7 +748,7 @@ namespace Microsoft.FSharp.Collections let inline sum (source:seq<'a>) : 'a = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'a,'a> (LanguagePrimitives.GenericZero) with + { new Composer.Core.Folder<'a,'a> (LanguagePrimitives.GenericZero) with override this.ProcessNext value = this.Value <- Checked.(+) this.Value value Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) @@ -2446,7 +758,7 @@ namespace Microsoft.FSharp.Collections let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + { new Composer.Core.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with override this.ProcessNext value = this.Value <- Checked.(+) this.Value (f value) Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) @@ -2456,7 +768,7 @@ namespace Microsoft.FSharp.Collections let inline average (source: seq< ^a>) : ^a = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'a, Composer.Internal.Values<'a, int>> (Composer.Internal.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + { new Composer.Core.Folder<'a, Composer.Core.Values<'a, int>> (Composer.Core.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 value this.Value._2 <- this.Value._2 + 1 @@ -2471,7 +783,7 @@ namespace Microsoft.FSharp.Collections let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,Composer.Internal.Values<'U, int>> (Composer.Internal.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + { new Composer.Core.Folder<'T,Composer.Core.Values<'U, int>> (Composer.Core.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 (f value) this.Value._2 <- this.Value._2 + 1 @@ -2491,7 +803,7 @@ namespace Microsoft.FSharp.Collections let inline min (source: seq<_>) = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2510,7 +822,7 @@ namespace Microsoft.FSharp.Collections let inline minBy (f : 'T -> 'U) (source: seq<'T>) : 'T = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with override this.ProcessNext value = match this.Value._1, f value with | true, valueU -> @@ -2549,7 +861,7 @@ namespace Microsoft.FSharp.Collections let inline max (source: seq<_>) = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2568,7 +880,7 @@ namespace Microsoft.FSharp.Collections let inline maxBy (f : 'T -> 'U) (source: seq<'T>) : 'T = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T,Composer.Internal.Values> (Composer.Internal.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with override this.ProcessNext value = match this.Value._1, f value with | true, valueU -> @@ -2606,15 +918,15 @@ namespace Microsoft.FSharp.Collections *) [] let takeWhile p (source: seq<_>) = - source |> seqFactory (Composer.TakeWhileFactory p) + source |> seqFactory (Composer.Seq.TakeWhileFactory p) [] let skip count (source: seq<_>) = - source |> seqFactory (Composer.SkipFactory count) + source |> seqFactory (Composer.Seq.SkipFactory count) [] let skipWhile p (source: seq<_>) = - source |> seqFactory (Composer.SkipWhileFactory p) + source |> seqFactory (Composer.Seq.SkipWhileFactory p) [] let forall2 p (source1: seq<_>) (source2: seq<_>) = @@ -2625,7 +937,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<_,bool> (true) with + { new Composer.Core.Folder<_,bool> (true) with override this.ProcessNext value = if (e2.MoveNext()) then if not (p.Invoke(value, e2.Current)) then @@ -2645,7 +957,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Internal.Folder<_,bool> (false) with + { new Composer.Core.Folder<_,bool> (false) with override this.ProcessNext value = if (e2.MoveNext()) then if p.Invoke(value, e2.Current) then @@ -2660,7 +972,7 @@ namespace Microsoft.FSharp.Collections let tryHead (source : seq<_>) = source |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Option<'T>> (None) with + { new Composer.Core.Folder<'T, Option<'T>> (None) with override this.ProcessNext value = this.Value <- Some value halt () @@ -2688,13 +1000,13 @@ namespace Microsoft.FSharp.Collections [] let tail (source: seq<'T>) = - source |> seqFactory (Composer.TailFactory ()) + source |> seqFactory (Composer.Seq.TailFactory ()) [] let tryLast (source : seq<_>) = source |> foreach (fun _ -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values(true, Unchecked.defaultof<'T>)) with + { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2716,7 +1028,7 @@ namespace Microsoft.FSharp.Collections let exactlyOne (source : seq<_>) = source |> foreach (fun halt -> - { new Composer.Internal.Folder<'T, Composer.Internal.Values> (Composer.Internal.Values(true, Unchecked.defaultof<'T>, false)) with + { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values(true, Unchecked.defaultof<'T>, false)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -2747,7 +1059,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.Reverse array array - Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedReverse) + Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedReverse) [] let permute f (source:seq<_>) = @@ -2756,7 +1068,7 @@ namespace Microsoft.FSharp.Collections source |> toArray |> Array.permute f - Composer.Helpers.upcastEnumerable (Composer.Array.createDelayedId delayedPermute) + Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedPermute) [] let mapFold<'T,'State,'Result> (f: 'State -> 'T -> 'Result * 'State) acc source = @@ -2774,7 +1086,7 @@ namespace Microsoft.FSharp.Collections [] let except (itemsToExclude: seq<'T>) (source: seq<'T>) = checkNonNull "itemsToExclude" itemsToExclude - source |> seqFactory (Composer.ExceptFactory itemsToExclude) + source |> seqFactory (Composer.Seq.ExceptFactory itemsToExclude) [] let chunkBySize chunkSize (source : seq<_>) = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index a84a71fc037..f06c676e4de 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -13,75 +13,6 @@ namespace Microsoft.FSharp.Collections [] [] module Seq = - module Composer = - module Internal = - /// PipeIdx denotes the index of the element within the pipeline. 0 denotes the - /// source of the chain. - type PipeIdx = int - type ``PipeIdx?`` = Nullable - - /// ICompletionChaining is used to correctly handle cleaning up of the pipeline. A - /// base implementation is provided in Consumer, and should not be overwritten. Consumer - /// provides it's own OnComplete and OnDispose function which should be used to handle - /// a particular consumers cleanup. - type ICompletionChaining = - /// OnComplete is used to determine if the object has been processed correctly, - /// and possibly throw exceptions to denote incorrect application (i.e. such as a Take - /// operation which didn't have a source at least as large as was required). It is - /// not called in the case of an exception being thrown whilst the stream is still - /// being processed. - abstract OnComplete : PipeIdx -> unit - /// OnDispose is used to cleanup the stream. It is always called at the last operation - /// after the enumeration has completed. - abstract OnDispose : unit -> unit - - type IOutOfBand = - abstract StopFurtherProcessing : PipeIdx -> unit - - /// Consumer is the base class of all elements within the pipeline - [] - type Consumer<'T,'U> = - interface ICompletionChaining - new : unit -> Consumer<'T,'U> - abstract member ProcessNext : input:'T -> bool - abstract member OnComplete : PipeIdx -> unit - abstract member OnDispose : unit -> unit - - /// Values is a mutable struct. It can be embedded within the folder type - /// if two values are required for the calculation. - [] - type Values<'a,'b> = - new : a:'a * b:'b -> Values<'a,'b> - val mutable _1: 'a - val mutable _2: 'b - - /// Values is a mutable struct. It can be embedded within the folder type - /// if three values are required for the calculation. - [] - type Values<'a,'b,'c> = - new : a:'a * b:'b * c:'c -> Values<'a,'b,'c> - val mutable _1: 'a - val mutable _2: 'b - val mutable _3: 'c - - /// Folder is a base class to assist with fold-like operations. It's intended usage - /// is as a base class for an object expression that will be used from within - /// the ForEach function. - [] - type Folder<'T,'U> = - inherit Consumer<'T,'T> - new : init:'U -> Folder<'T,'U> - val mutable Value: 'U - - type ISeqFactory<'T,'U> = - abstract member Create : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> - abstract member PipeIdx : PipeIdx - - type ISeq<'T> = - inherit System.Collections.Generic.IEnumerable<'T> - abstract member Compose : ISeqFactory<'T,'U> -> ISeq<'U> - abstract member ForEach : f:((unit -> unit) -> 'a) -> 'a when 'a :> Consumer<'T,'T> - /// Returns a new sequence that contains the cartesian product of the two input sequences. /// The first sequence. /// The second sequence. @@ -1273,7 +1204,7 @@ namespace Microsoft.FSharp.Collections /// /// Thrown when the input sequence is null. [] - val toComposer : source:seq<'T> -> Composer.Internal.ISeq<'T> + val toComposer : source:seq<'T> -> Composer.Core.ISeq<'T> /// Builds a list from the given collection. /// @@ -1419,4 +1350,4 @@ namespace Microsoft.FSharp.Collections /// /// Thrown when any of the input sequences is null. [] - val zip3: source1:seq<'T1> -> source2:seq<'T2> -> source3:seq<'T3> -> seq<'T1 * 'T2 * 'T3> + val zip3: source1:seq<'T1> -> source2:seq<'T2> -> source3:seq<'T3> -> seq<'T1 * 'T2 * 'T3> \ No newline at end of file diff --git a/src/fsharp/FSharp.Core/seqcomposer.fs b/src/fsharp/FSharp.Core/seqcomposer.fs index 6ebe4e26cf8..3f36e2c1469 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fs +++ b/src/fsharp/FSharp.Core/seqcomposer.fs @@ -14,17 +14,21 @@ namespace Microsoft.FSharp.Collections open Microsoft.FSharp.Control open Microsoft.FSharp.Collections open Microsoft.FSharp.Primitives.Basics - + [] module Composer = open IEnumerator module Core = - type PipeIdx = int + type PipeIdx = int + type ``PipeIdx?`` = Nullable + let emptyPipeIdx = Nullable () + let inline getPipeIdx (maybePipeIdx:``PipeIdx?``) = if maybePipeIdx.HasValue then maybePipeIdx.Value else 1 + let inline makePipeIdx (pipeIdx:PipeIdx) = Nullable pipeIdx type ICompletionChaining = - abstract OnComplete : stopTailCall:byref * PipeIdx -> unit - abstract OnDispose : stopTailCall:byref -> unit + abstract OnComplete : PipeIdx -> unit + abstract OnDispose : unit -> unit type IOutOfBand = abstract StopFurtherProcessing : PipeIdx -> unit @@ -34,16 +38,16 @@ namespace Microsoft.FSharp.Collections abstract ProcessNext : input:'T -> bool abstract OnComplete : PipeIdx -> unit - abstract OnDispose : unit -> unit + abstract OnDispose : unit -> unit default __.OnComplete _ = () default __.OnDispose () = () interface ICompletionChaining with - member this.OnComplete (_, terminatingIdx) = + member this.OnComplete terminatingIdx = this.OnComplete terminatingIdx - member this.OnDispose _ = + member this.OnDispose () = try this.OnDispose () finally () @@ -80,209 +84,266 @@ namespace Microsoft.FSharp.Collections Value = init } - [] - type SeqFactory<'T,'U> () = + type ISeqFactory<'T,'U> = abstract PipeIdx : PipeIdx - abstract Create<'V> : IOutOfBand -> PipeIdx -> Consumer<'U,'V> -> Consumer<'T,'V> - - default __.PipeIdx = 1 - - member this.Build outOfBand next = this.Create outOfBand 1 next + abstract Create<'V> : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> type ISeq<'T> = inherit IEnumerable<'T> - abstract member Compose<'U> : (SeqFactory<'T,'U>) -> ISeq<'U> + abstract member Compose<'U> : (ISeqFactory<'T,'U>) -> ISeq<'U> abstract member ForEach<'consumer when 'consumer :> Consumer<'T,'T>> : f:((unit->unit)->'consumer) -> 'consumer open Core - module internal TailCall = + module internal Helpers = // used for performance reasons; these are not recursive calls, so should be safe // ** it should be noted that potential changes to the f# compiler may render this function // ineffictive ** - let inline avoid boolean = match boolean with true -> true | false -> false + let inline avoidTailCall boolean = match boolean with true -> true | false -> false - module internal Upcast = // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality // is fixed with the compiler then these functions can be removed. - let inline seq (t:#ISeq<'T>) : ISeq<'T> = (# "" t : ISeq<'T> #) - let inline enumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) - let inline enumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) - let inline enumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) - let inline iCompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) + let inline upcastSeq (t:#ISeq<'T>) : ISeq<'T> = (# "" t : ISeq<'T> #) + let inline upcastFactory (t:#ISeqFactory<'T,'U>) : ISeqFactory<'T,'U> = (# "" t : ISeqFactory<'T,'U> #) + let inline upcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) + let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) + let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) + let inline upcastICompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) + + open Helpers module internal Seq = - type ComposedFactory<'T,'U,'V> private (first:SeqFactory<'T,'U>, second:SeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = - inherit SeqFactory<'T,'V>() + type [] SeqComponentFactory<'T,'U> (pipeIdx:``PipeIdx?``) = + new() = SeqComponentFactory<'T,'U> (emptyPipeIdx) + + interface ISeqFactory<'T,'U> with + member __.PipeIdx = getPipeIdx pipeIdx + member __.Create<'V> (_:IOutOfBand) (_:``PipeIdx?``) (_:Consumer<'U,'V>) : Consumer<'T,'V> = failwith "library implementation error: Create on base factory should not be called" - override __.PipeIdx = - secondPipeIdx + and ComposedFactory<'T,'U,'V> private (first:ISeqFactory<'T,'U>, second:ISeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = + inherit SeqComponentFactory<'T,'V> (makePipeIdx secondPipeIdx) - override this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'V,'W>) : Consumer<'T,'W> = - first.Create outOfBand pipeIdx (second.Create outOfBand secondPipeIdx next) + interface ISeqFactory<'T,'V> with + member this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'V,'W>) : Consumer<'T,'W> = + first.Create outOfBand pipeIdx (second.Create outOfBand (makePipeIdx secondPipeIdx) next) - static member Combine (first:SeqFactory<'T,'U>) (second:SeqFactory<'U,'V>) : SeqFactory<'T,'V> = - upcast ComposedFactory(first, second, first.PipeIdx+1) + static member Combine (first:ISeqFactory<'T,'U>) (second:ISeqFactory<'U,'V>) : ISeqFactory<'T,'V> = + ComposedFactory(first, second, first.PipeIdx+1) |> upcastFactory and ChooseFactory<'T,'U> (filter:'T->option<'U>) = - inherit SeqFactory<'T,'U> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) + inherit SeqComponentFactory<'T,'U> () + interface ISeqFactory<'T,'U> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) and DistinctFactory<'T when 'T: equality> () = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) + + and FilterFactory<'T> (filter:'T->bool) = + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = + match next with + | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter + | _ -> upcast Filter (filter, next) and IdentityFactory<'T> () = - inherit SeqFactory<'T,'T> () - static let singleton : SeqFactory<'T,'T> = upcast (IdentityFactory<'T>()) - override __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next + inherit SeqComponentFactory<'T,'T> () + static let singleton = IdentityFactory<'T>() + interface ISeqFactory<'T,'T> with + member __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next static member Instance = singleton + and MapFactory<'T,'U> (map:'T->'U) = + inherit SeqComponentFactory<'T,'U> () + interface ISeqFactory<'T,'U> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = + match next with + | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map + | _ -> upcast Map<_,_,_> (map, next) + and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = - inherit SeqFactory<'First,'U> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, outOfBand, next, pipeIdx) + inherit SeqComponentFactory<'First,'U> () + interface ISeqFactory<'First,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, outOfBand, next, getPipeIdx pipeIdx) and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = - inherit SeqFactory<'Second,'U> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, outOfBand, next, pipeIdx) + inherit SeqComponentFactory<'Second,'U> () + interface ISeqFactory<'Second,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, outOfBand, next, getPipeIdx pipeIdx) and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = - inherit SeqFactory<'First,'U> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, outOfBand, next, pipeIdx) + inherit SeqComponentFactory<'First,'U> () + interface ISeqFactory<'First,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, outOfBand, next, getPipeIdx pipeIdx) + + and MapiFactory<'T,'U> (mapi:int->'T->'U) = + inherit SeqComponentFactory<'T,'U> () + interface ISeqFactory<'T,'U> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Mapi (mapi, next) and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = - inherit SeqFactory<'First,'U> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, outOfBand, next, pipeIdx) + inherit SeqComponentFactory<'First,'U> () + interface ISeqFactory<'First,'U> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, outOfBand, next, getPipeIdx pipeIdx) and PairwiseFactory<'T> () = - inherit SeqFactory<'T,'T*'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) + inherit SeqComponentFactory<'T,'T*'T> () + interface ISeqFactory<'T,'T*'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) and ScanFactory<'T,'State> (folder:'State->'T->'State, initialState:'State) = - inherit SeqFactory<'T,'State> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) + inherit SeqComponentFactory<'T,'State> () + interface ISeqFactory<'T,'State> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) - and SkipFactory<'T> (count:int, onNotEnoughElements) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, onNotEnoughElements, next) + and SkipFactory<'T> (count:int) = + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, next) and SkipWhileFactory<'T> (predicate:'T->bool) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) and TakeWhileFactory<'T> (predicate:'T->bool) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, outOfBand, next, pipeIdx) + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, outOfBand, next, getPipeIdx pipeIdx) and TakeFactory<'T> (count:int) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, outOfBand, next, pipeIdx) + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, outOfBand, next, getPipeIdx pipeIdx) and TailFactory<'T> () = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) and TruncateFactory<'T> (count:int) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, pipeIdx) + inherit SeqComponentFactory<'T,'T> () + interface ISeqFactory<'T,'T> with + member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, getPipeIdx pipeIdx) and WindowedFactory<'T> (windowSize:int) = - inherit SeqFactory<'T, 'T[]> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T[],'V>) : Consumer<'T,'V> = upcast Windowed (windowSize, next) + inherit SeqComponentFactory<'T, 'T[]> () + interface ISeqFactory<'T, 'T[]> with + member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T[],'V>) : Consumer<'T,'V> = upcast Windowed (windowSize, next) + + and [] SeqComponent<'T,'U> (next:ICompletionChaining) = + inherit Consumer<'T,'U>() - and ISkipping = // Seq.init(Infinite)? lazily uses Current. The only Composer component that can do that is Skip // and it can only do it at the start of a sequence abstract Skipping : unit -> bool - and [] SeqComponentSimple<'T,'U> (next:ICompletionChaining) = - inherit Consumer<'T,'U>() + abstract CreateMap<'S> : map:('S->'T) -> SeqComponent<'S,'U> + abstract CreateFilter : filter:('T->bool) -> SeqComponent<'T,'U> interface ICompletionChaining with - member this.OnComplete (stopTailCall, terminatingIdx) = - next.OnComplete (&stopTailCall, terminatingIdx) - member this.OnDispose stopTailCall = - next.OnDispose (&stopTailCall) - - and [] SeqComponentSimpleValue<'T,'U,'Value> = - inherit SeqComponentSimple<'T,'U> - - val mutable Value : 'Value - - new (next, init) = { - inherit SeqComponentSimple<'T,'U>(next) - Value = init - } - - and [] SeqComponent<'T,'U> (next:ICompletionChaining) = - inherit Consumer<'T,'U>() - - interface ICompletionChaining with - member this.OnComplete (stopTailCall, terminatingIdx) = + member this.OnComplete terminatingIdx = this.OnComplete terminatingIdx - next.OnComplete (&stopTailCall, terminatingIdx) - member this.OnDispose stopTailCall = + next.OnComplete terminatingIdx + member this.OnDispose () = try this.OnDispose () - finally next.OnDispose (&stopTailCall) + finally next.OnDispose () + + default __.Skipping () = false + + default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) + default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) and Choose<'T,'U,'V> (choose:'T->option<'U>, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = match choose input with - | Some value -> TailCall.avoid (next.ProcessNext value) + | Some value -> avoidTailCall (next.ProcessNext value) | None -> false and Distinct<'T,'V when 'T: equality> (next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'T,'V>(next) let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) override __.ProcessNext (input:'T) : bool = if hashSet.Add input then - TailCall.avoid (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else false and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'T,'V>(next) let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) override __.ProcessNext (input:'T) : bool = if hashSet.Add(keyFunction input) then - TailCall.avoid (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else false and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'T,'V>(next) let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) override __.ProcessNext (input:'T) : bool = if cached.Value.Add input then - TailCall.avoid (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else false + and Filter<'T,'V> (filter:'T->bool, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) + + override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) + + override __.ProcessNext (input:'T) : bool = + if filter input then + avoidTailCall (next.ProcessNext input) + else + false + + and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + if filter input then + avoidTailCall (next.ProcessNext (map input)) + else + false + + and Map<'T,'U,'V> (map:'T->'U, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) + + override __.ProcessNext (input:'T) : bool = + avoidTailCall (next.ProcessNext (map input)) + and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map override __.ProcessNext (input:'First) : bool = if input2.MoveNext () then - TailCall.avoid (next.ProcessNext (map'.Invoke (input, input2.Current))) + avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -291,14 +352,14 @@ namespace Microsoft.FSharp.Collections input2.Dispose () and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'Second,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'Second,'V>(next) let input1 = enumerable1.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map override __.ProcessNext (input:'Second) : bool = if input1.MoveNext () then - TailCall.avoid (next.ProcessNext (map'.Invoke (input1.Current, input))) + avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -307,7 +368,7 @@ namespace Microsoft.FSharp.Collections input1.Dispose () and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'First,'V>(next) let input2 = enumerable2.GetEnumerator () let input3 = enumerable3.GetEnumerator () @@ -315,7 +376,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'First) : bool = if input2.MoveNext () && input3.MoveNext () then - TailCall.avoid (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) + avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -324,8 +385,28 @@ namespace Microsoft.FSharp.Collections try input2.Dispose () finally input3.Dispose () + and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + override __.ProcessNext (input:'T) : bool = + let u = map input + if filter u then + avoidTailCall (next.ProcessNext u) + else + false + + and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:Consumer<'U,'V>) = + inherit SeqComponent<'T,'V>(next) + + let mutable idx = 0 + let mapi' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt mapi + + override __.ProcessNext (input:'T) : bool = + idx <- idx + 1 + avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) + and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'First,'V>(next) let mutable idx = 0 let input2 = enumerable2.GetEnumerator () @@ -334,7 +415,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'First) : bool = if input2.MoveNext () then idx <- idx + 1 - TailCall.avoid (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) + avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -343,7 +424,7 @@ namespace Microsoft.FSharp.Collections input2.Dispose () and Pairwise<'T,'V> (next:Consumer<'T*'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'T,'V>(next) let mutable isFirst = true let mutable lastValue = Unchecked.defaultof<'T> @@ -356,46 +437,45 @@ namespace Microsoft.FSharp.Collections else let currentPair = lastValue, input lastValue <- input - TailCall.avoid (next.ProcessNext currentPair) + avoidTailCall (next.ProcessNext currentPair) and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:Consumer<'State,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'T,'V>(next) let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let mutable foldResult = initialState override __.ProcessNext (input:'T) : bool = foldResult <- f.Invoke(foldResult, input) - TailCall.avoid (next.ProcessNext foldResult) + avoidTailCall (next.ProcessNext foldResult) - and Skip<'T,'V> (skipCount:int, notEnoughElements:string->array->unit, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) + and Skip<'T,'V> (skipCount:int, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(next) let mutable count = 0 - interface ISkipping with - member __.Skipping () = - if count < skipCount then - count <- count + 1 - true - else - false + override __.Skipping () = + if count < skipCount then + count <- count + 1 + true + else + false override __.ProcessNext (input:'T) : bool = if count < skipCount then count <- count + 1 false else - TailCall.avoid (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) override __.OnComplete _ = if count < skipCount then let x = skipCount - count - notEnoughElements "{0}\ntried to skip {1} {2} past the end of the seq" + invalidOpFmt "tried to skip {0} {1} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] and SkipWhile<'T,'V> (predicate:'T->bool, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'T,'V>(next) let mutable skip = true @@ -405,9 +485,9 @@ namespace Microsoft.FSharp.Collections if skip then false else - TailCall.avoid (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else - TailCall.avoid (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) and Take<'T,'V> (takeCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipelineIdx:int) = inherit Truncate<'T, 'V>(takeCount, outOfBand, next, pipelineIdx) @@ -419,17 +499,17 @@ namespace Microsoft.FSharp.Collections [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] and TakeWhile<'T,'V> (predicate:'T->bool, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'T,'V>(next) override __.ProcessNext (input:'T) : bool = if predicate input then - TailCall.avoid (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else outOfBand.StopFurtherProcessing pipeIdx false and Tail<'T, 'V> (next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'T,'V>(next) let mutable first = true @@ -438,14 +518,14 @@ namespace Microsoft.FSharp.Collections first <- false false else - TailCall.avoid (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) override this.OnComplete _ = if first then invalidArg "source" (SR.GetString(SR.notEnoughElements)) and Truncate<'T,'V> (truncateCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'T,'V>(next) let mutable count = 0 @@ -456,13 +536,13 @@ namespace Microsoft.FSharp.Collections count <- count + 1 if count = truncateCount then outOfBand.StopFurtherProcessing pipeIdx - TailCall.avoid (next.ProcessNext input) + avoidTailCall (next.ProcessNext input) else outOfBand.StopFurtherProcessing pipeIdx false and Windowed<'T,'V> (windowSize: int, next:Consumer<'T[],'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) + inherit SeqComponent<'T,'V>(next) let circularBuffer = Array.zeroCreateUnchecked windowSize let mutable idx = 0 @@ -482,12 +562,12 @@ namespace Microsoft.FSharp.Collections else if windowSize < 32 then let window = Array.init windowSize (fun i -> circularBuffer.[(idx+i) % windowSize]) - TailCall.avoid (next.ProcessNext window) + avoidTailCall (next.ProcessNext window) else let window = Array.zeroCreateUnchecked windowSize Array.Copy(circularBuffer, idx, window, 0, windowSize - idx) Array.Copy(circularBuffer, 0, window, windowSize - idx, idx) - TailCall.avoid (next.ProcessNext window) + avoidTailCall (next.ProcessNext window) type SeqProcessNextStates = | InProcess = 0 @@ -549,8 +629,8 @@ namespace Microsoft.FSharp.Collections iterate state let makeIsSkipping (consumer:Consumer<'T,'U>) = - match box consumer with - | :? ISkipping as skip -> skip.Skipping + match consumer with + | :? SeqComponent<'T,'U> as c -> c.Skipping | _ -> fun () -> false let init f (terminatingIdx:int) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = @@ -561,23 +641,21 @@ namespace Microsoft.FSharp.Collections if maybeSkipping then maybeSkipping <- isSkipping () - if not maybeSkipping then + if (not maybeSkipping) then consumer.ProcessNext (f (idx+1)) |> ignore idx <- idx + 1 - let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:SeqFactory<'T,'U>) executeOn = + let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:ISeqFactory<'T,'U>) executeOn = let pipeline = OutOfBand() let result = f (fun () -> (pipeline:>IOutOfBand).StopFurtherProcessing (current.PipeIdx+1)) - let consumer = current.Build pipeline result + let consumer = current.Create pipeline emptyPipeIdx result try executeOn pipeline consumer - let mutable stopTailCall = () - (Upcast.iCompletionChaining consumer).OnComplete (&stopTailCall, pipeline.HaltedIdx) + (upcastICompletionChaining consumer).OnComplete pipeline.HaltedIdx result finally - let mutable stopTailCall = () - (Upcast.iCompletionChaining consumer).OnDispose (&stopTailCall) + (upcastICompletionChaining consumer).OnDispose () module Enumerable = type Empty<'T>() = @@ -599,11 +677,10 @@ namespace Microsoft.FSharp.Collections type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ICompletionChaining) = interface IDisposable with member __.Dispose() : unit = - let mutable stopTailCall = () - seqComponent.OnDispose (&stopTailCall) + seqComponent.OnDispose () interface IEnumerator with - member this.Current : obj = box ((Upcast.enumerator this)).Current + member this.Current : obj = box ((upcastEnumerator this)).Current member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)" member __.Reset () : unit = noReset () @@ -622,13 +699,13 @@ namespace Microsoft.FSharp.Collections abstract member Append : (seq<'T>) -> IEnumerable<'T> - default this.Append source = Upcast.enumerable (AppendEnumerable [this; source]) + default this.Append source = upcastEnumerable (AppendEnumerable [this; source]) interface IEnumerable with member this.GetEnumerator () : IEnumerator = - let genericEnumerable = Upcast.enumerable this + let genericEnumerable = upcastEnumerable this let genericEnumerator = genericEnumerable.GetEnumerator () - Upcast.enumeratorNonGeneric genericEnumerator + upcastEnumeratorNonGeneric genericEnumerator interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement () @@ -648,8 +725,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - let mutable stopTailCall = () - (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -662,20 +738,19 @@ namespace Microsoft.FSharp.Collections try source.Dispose () finally - let mutable stopTailCall = () - (Upcast.iCompletionChaining seqComponent).OnDispose (&stopTailCall) + (upcastICompletionChaining seqComponent).OnDispose () - and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqFactory<'T,'U>) = + and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:ISeqFactory<'T,'U>) = inherit EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Build result (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with - member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) + member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + upcastSeq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.enumerable enumerable) @@ -707,7 +782,7 @@ namespace Microsoft.FSharp.Collections | _ -> failwith "library implementation error: all states should have been handled" interface IEnumerator with - member this.Current = box ((Upcast.enumerator this)).Current + member this.Current = box ((upcastEnumerator this)).Current member __.MoveNext () = state <- SeqProcessNextStates.InProcess moveNext () @@ -723,14 +798,14 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = - Upcast.enumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) + upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) override this.Append source = - Upcast.enumerable (AppendEnumerable (source :: sources)) + upcastEnumerable (AppendEnumerable (source :: sources)) interface ISeq<'T> with - member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = - Upcast.seq (Enumerable<'T,'V>(this, next)) + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + upcastSeq (Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) @@ -740,17 +815,17 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = - Upcast.enumerator (new ConcatEnumerator<_,_> (sources)) + upcastEnumerator (new ConcatEnumerator<_,_> (sources)) interface ISeq<'T> with - member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = - Upcast.seq (Enumerable<'T,'V>(this, next)) + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + upcastSeq (Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) let create enumerable current = - Upcast.seq (Enumerable(enumerable, current)) + upcastSeq (Enumerable(enumerable, current)) module EmptyEnumerable = type Enumerable<'T> () = @@ -763,11 +838,11 @@ namespace Microsoft.FSharp.Collections member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>() override this.Append source = - Upcast.enumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) + upcastEnumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) interface ISeq<'T> with - member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = - Upcast.seq (Enumerable.Enumerable<'T,'V>(this, next)) + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + upcastSeq (Enumerable.Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) @@ -798,8 +873,7 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - let mutable stopTailCall = () - (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -807,25 +881,25 @@ namespace Microsoft.FSharp.Collections initMoveNext () moveNext () - type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqFactory<'T,'U>) = + type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:ISeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U>(delayedArray, current.Build result (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with - member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) + member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + upcastSeq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.array (delayedArray ())) - let createDelayed (delayedArray:unit->array<'T>) (current:SeqFactory<'T,'U>) = - Upcast.seq (Enumerable(delayedArray, current)) + let createDelayed (delayedArray:unit->array<'T>) (current:ISeqFactory<'T,'U>) = + upcastSeq (Enumerable(delayedArray, current)) - let create (array:array<'T>) (current:SeqFactory<'T,'U>) = + let create (array:array<'T>) (current:ISeqFactory<'T,'U>) = createDelayed (fun () -> array) current let createDelayedId (delayedArray:unit -> array<'T>) = @@ -850,8 +924,7 @@ namespace Microsoft.FSharp.Collections moveNext tail | _ -> result.SeqState <- SeqProcessNextStates.Finished - let mutable stopTailCall = () - (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -859,23 +932,23 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext list - type Enumerable<'T,'U>(alist:list<'T>, current:SeqFactory<'T,'U>) = + type Enumerable<'T,'U>(alist:list<'T>, current:ISeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U>(alist, current.Build result (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with - member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) + member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + upcastSeq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.list alist) let create alist current = - Upcast.seq (Enumerable(alist, current)) + upcastSeq (Enumerable(alist, current)) module Unfold = type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, result:Result<'U>) = @@ -898,17 +971,17 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext () - type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqFactory<'T,'U>) = + type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:ISeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Build result (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with - member this.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + upcastSeq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.unfold generator state) @@ -964,8 +1037,7 @@ namespace Microsoft.FSharp.Collections raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) else result.SeqState <- SeqProcessNextStates.Finished - let mutable stopTailCall = () - (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) + (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx false interface IEnumerator with @@ -973,17 +1045,17 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext () - type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqFactory<'T,'U>) = + type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:ISeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U>(count, f, current.Build result (SetResult<'U> result), result)) + upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) interface ISeq<'U> with - member this.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = + upcastSeq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) member this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = let terminatingIdx = getTerminatingIdx count @@ -1050,25 +1122,25 @@ namespace Microsoft.FSharp.Collections upto (if count.HasValue then Some (count.Value-1) else None) f interface ISeq<'T> with - member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = - Upcast.seq (Enumerable<'T,'V>(count, f, next)) + member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = + upcastSeq (Enumerable<'T,'V>(count, f, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (Upcast.enumerable this)) + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (upcastEnumerable this)) [] let toComposer (source:seq<'T>) : ISeq<'T> = + checkNonNull "source" source match source with | :? ISeq<'T> as s -> s - | :? array<'T> as a -> Upcast.seq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) - | :? list<'T> as a -> Upcast.seq (List.Enumerable(a, IdentityFactory.Instance)) - | null -> nullArg "source" - | _ -> Upcast.seq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) + | :? array<'T> as a -> upcastSeq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) + | :? list<'T> as a -> upcastSeq (List.Enumerable(a, IdentityFactory.Instance)) + | _ -> upcastSeq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) let inline foreach f (source:ISeq<_>) = source.ForEach f - let inline compose (factory:#SeqFactory<_,_>) (source:ISeq<'T>) = + let inline compose factory (source:ISeq<'T>) = source.Compose factory [] @@ -1076,17 +1148,17 @@ namespace Microsoft.FSharp.Collections [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> = - Upcast.seq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) + upcastSeq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) [] let initInfinite<'T> (f:int->'T) : ISeq<'T> = - Upcast.seq (new Init.EnumerableDecider<'T>(Nullable (), f)) + upcastSeq (new Init.EnumerableDecider<'T>(Nullable (), f)) [] let init<'T> (count:int) (f:int->'T) : ISeq<'T> = if count < 0 then invalidArgInputMustBeNonNegative "count" count elif count = 0 then empty else - Upcast.seq (new Init.EnumerableDecider<'T>(Nullable count, f)) + upcastSeq (new Init.EnumerableDecider<'T>(Nullable count, f)) [] let iter f (source:ISeq<'T>) = @@ -1098,22 +1170,20 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> ignore - [] - let tryHead (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, Option<'T>> (None) with - override this.ProcessNext value = - this.Value <- Some value - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun head -> head.Value - [] let tryItem i (source:ISeq<'T>) = if i < 0 then None else - source.Compose (SkipFactory(i, fun _ _ -> ())) - |> tryHead + source + |> foreach (fun halt -> + { new Folder<'T, Values>> (Values<_,_> (0, None)) with + override this.ProcessNext value = + if this.Value._1 = i then + this.Value._2 <- Some value + halt () + else + this.Value._1 <- this.Value._1 + 1 + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun item -> item.Value._2 [] let iteri f (source:ISeq<'T>) = @@ -1163,40 +1233,21 @@ namespace Microsoft.FSharp.Collections halt () Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun forall -> forall.Value - + [] - let inline filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { new SeqComponentSimple<'T,'V>(Upcast.iCompletionChaining next) with - member __.ProcessNext input = - if f input then TailCall.avoid (next.ProcessNext input) - else false } } + let filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = + source + |> compose (FilterFactory f) [] - let inline map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = - source |> compose { new SeqFactory<'T,'U>() with - member __.Create _ _ next = - upcast { new SeqComponentSimple<'T,'V>(Upcast.iCompletionChaining next) with - member __.ProcessNext input = - TailCall.avoid (next.ProcessNext (f input)) } } + let map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = + source + |> compose (MapFactory f) [] - let inline mapi f source = - source |> compose { new SeqFactory<'T,'U>() with - member __.Create _ _ next = - upcast { new SeqComponentSimpleValue<'T,'V,int>(Upcast.iCompletionChaining next, -1) with - override this.ProcessNext (input:'T) : bool = - this.Value <- this.Value + 1 - TailCall.avoid (next.ProcessNext (f this.Value input)) } } - - let mapi_adapt (f:OptimizedClosures.FSharpFunc<_,_,_>) source = - source |> compose { new SeqFactory<'T,'U>() with - member __.Create _ _ next = - upcast { new SeqComponentSimpleValue<'T,'V,int>(Upcast.iCompletionChaining next, -1) with - override this.ProcessNext (input:'T) : bool = - this.Value <- this.Value + 1 - TailCall.avoid (next.ProcessNext (f.Invoke (this.Value, input))) } } + let mapi f source = + source + |> compose (MapiFactory f) [] let choose f source = @@ -1204,8 +1255,9 @@ namespace Microsoft.FSharp.Collections |> compose (ChooseFactory f) [] - let inline indexed source = - mapi (fun i x -> i,x) source + let indexed source = + source + |> compose (MapiFactory (fun i x -> i,x)) [] let tryPick f (source:ISeq<'T>) = diff --git a/src/fsharp/FSharp.Core/seqcomposer.fsi b/src/fsharp/FSharp.Core/seqcomposer.fsi index c9bdf2fdb3e..838cee6da37 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fsi +++ b/src/fsharp/FSharp.Core/seqcomposer.fsi @@ -14,6 +14,7 @@ namespace Microsoft.FSharp.Collections /// PipeIdx denotes the index of the element within the pipeline. 0 denotes the /// source of the chain. type PipeIdx = int + type ``PipeIdx?`` = Nullable /// ICompletionChaining is used to correctly handle cleaning up of the pipeline. A /// base implementation is provided in Consumer, and should not be overwritten. Consumer @@ -25,10 +26,10 @@ namespace Microsoft.FSharp.Collections /// operation which didn't have a source at least as large as was required). It is /// not called in the case of an exception being thrown whilst the stream is still /// being processed. - abstract OnComplete : stopTailCall:byref*PipeIdx -> unit + abstract OnComplete : PipeIdx -> unit /// OnDispose is used to cleanup the stream. It is always called at the last operation /// after the enumeration has completed. - abstract OnDispose : stopTailCall:byref -> unit + abstract OnDispose : unit -> unit type IOutOfBand = abstract StopFurtherProcessing : PipeIdx -> unit @@ -70,160 +71,204 @@ namespace Microsoft.FSharp.Collections new : init:'U -> Folder<'T,'U> val mutable Value: 'U - [] - type SeqFactory<'T,'U> = - new : unit -> SeqFactory<'T,'U> - abstract PipeIdx : PipeIdx - abstract member Create : IOutOfBand -> PipeIdx -> Consumer<'U,'V> -> Consumer<'T,'V> + type ISeqFactory<'T,'U> = + abstract member Create : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> + abstract member PipeIdx : PipeIdx type ISeq<'T> = inherit System.Collections.Generic.IEnumerable<'T> - abstract member Compose : SeqFactory<'T,'U> -> ISeq<'U> + abstract member Compose : ISeqFactory<'T,'U> -> ISeq<'U> abstract member ForEach : f:((unit -> unit) -> 'a) -> 'a when 'a :> Consumer<'T,'T> open Core + module internal Helpers = + val inline avoidTailCall : boolean:bool -> bool + val inline upcastSeq : t: #ISeq<'T> -> ISeq<'T> + val inline upcastFactory : + t: #ISeqFactory<'T,'U> -> ISeqFactory<'T,'U> + val inline upcastEnumerable : t:#IEnumerable<'T> -> IEnumerable<'T> + val inline upcastEnumerator : t:#IEnumerator<'T> ->IEnumerator<'T> + val inline upcastEnumeratorNonGeneric : + t:#IEnumerator -> IEnumerator + val inline upcastICompletionChaining : + t: #ICompletionChaining -> ICompletionChaining + module internal Seq = - type ComposedFactory<'T,'U,'V> = + [] + type SeqComponentFactory<'T,'U> = class - inherit SeqFactory<'T,'V> - private new : first: SeqFactory<'T,'U> * - second: SeqFactory<'U,'V> * + interface ISeqFactory<'T,'U> + new : unit -> SeqComponentFactory<'T,'U> + new : pipeIdx: ``PipeIdx?`` -> + SeqComponentFactory<'T,'U> + end + and ComposedFactory<'T,'U,'V> = + class + inherit SeqComponentFactory<'T,'V> + interface ISeqFactory<'T,'V> + private new : first: ISeqFactory<'T,'U> * + second: ISeqFactory<'U,'V> * secondPipeIdx: PipeIdx -> ComposedFactory<'T,'U,'V> static member - Combine : first: SeqFactory<'T,'U> -> - second: SeqFactory<'U,'V> -> - SeqFactory<'T,'V> + Combine : first: ISeqFactory<'T,'U> -> + second: ISeqFactory<'U,'V> -> + ISeqFactory<'T,'V> end and ChooseFactory<'T,'U> = class - inherit SeqFactory<'T,'U> + inherit SeqComponentFactory<'T,'U> + interface ISeqFactory<'T,'U> new : filter:('T -> 'U option) -> ChooseFactory<'T,'U> end and DistinctFactory<'T when 'T : equality> = class - inherit SeqFactory<'T,'T> + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> new : unit -> DistinctFactory<'T> end and DistinctByFactory<'T,'Key when 'Key : equality> = class - inherit SeqFactory<'T,'T> + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> new : keyFunction:('T -> 'Key) -> DistinctByFactory<'T,'Key> end and ExceptFactory<'T when 'T : equality> = class - inherit SeqFactory<'T,'T> + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> new : itemsToExclude:seq<'T> -> ExceptFactory<'T> end + and FilterFactory<'T> = + class + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> + new : filter:('T -> bool) -> FilterFactory<'T> + end and IdentityFactory<'T> = class - inherit SeqFactory<'T,'T> + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> new : unit -> IdentityFactory<'T> - static member Instance : SeqFactory<'T,'T> + static member Instance : IdentityFactory<'T> + end + and MapFactory<'T,'U> = + class + inherit SeqComponentFactory<'T,'U> + interface ISeqFactory<'T,'U> + new : map:('T -> 'U) -> MapFactory<'T,'U> end and Map2FirstFactory<'First,'Second,'U> = class - inherit SeqFactory<'First,'U> + inherit SeqComponentFactory<'First,'U> + interface ISeqFactory<'First,'U> new : map:('First -> 'Second -> 'U) * input2:IEnumerable<'Second> -> Map2FirstFactory<'First,'Second,'U> end and Map2SecondFactory<'First,'Second,'U> = class - inherit SeqFactory<'Second,'U> + inherit SeqComponentFactory<'Second,'U> + interface ISeqFactory<'Second,'U> new : map:('First -> 'Second -> 'U) * input1:IEnumerable<'First> -> Map2SecondFactory<'First,'Second,'U> end and Map3Factory<'First,'Second,'Third,'U> = class - inherit SeqFactory<'First,'U> + inherit SeqComponentFactory<'First,'U> + interface ISeqFactory<'First,'U> new : map:('First -> 'Second -> 'Third -> 'U) * input2:IEnumerable<'Second> * input3:IEnumerable<'Third> -> Map3Factory<'First,'Second,'Third,'U> end + and MapiFactory<'T,'U> = + class + inherit SeqComponentFactory<'T,'U> + interface ISeqFactory<'T,'U> + new : mapi:(int -> 'T -> 'U) -> MapiFactory<'T,'U> + end and Mapi2Factory<'First,'Second,'U> = class - inherit SeqFactory<'First,'U> + inherit SeqComponentFactory<'First,'U> + interface ISeqFactory<'First,'U> new : map:(int -> 'First -> 'Second -> 'U) * input2:IEnumerable<'Second> -> Mapi2Factory<'First,'Second,'U> end and PairwiseFactory<'T> = class - inherit SeqFactory<'T,('T * 'T)> + inherit SeqComponentFactory<'T,('T * 'T)> + interface ISeqFactory<'T,('T * 'T)> new : unit -> PairwiseFactory<'T> end and ScanFactory<'T,'State> = class - inherit SeqFactory<'T,'State> + inherit SeqComponentFactory<'T,'State> + interface ISeqFactory<'T,'State> new : folder:('State -> 'T -> 'State) * initialState:'State -> ScanFactory<'T,'State> end and SkipFactory<'T> = class - inherit SeqFactory<'T,'T> - new : count:int * notEnoughElements:(string->array->unit) -> SkipFactory<'T> + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> + new : count:int -> SkipFactory<'T> end and SkipWhileFactory<'T> = class - inherit SeqFactory<'T,'T> + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> new : predicate:('T -> bool) -> SkipWhileFactory<'T> end and TakeWhileFactory<'T> = class - inherit SeqFactory<'T,'T> + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> new : predicate:('T -> bool) -> TakeWhileFactory<'T> end and TakeFactory<'T> = class - inherit SeqFactory<'T,'T> + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> new : count:int -> TakeFactory<'T> end and TailFactory<'T> = class - inherit SeqFactory<'T,'T> + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> new : unit -> TailFactory<'T> end and TruncateFactory<'T> = class - inherit SeqFactory<'T,'T> + inherit SeqComponentFactory<'T,'T> + interface ISeqFactory<'T,'T> new : count:int -> TruncateFactory<'T> end and WindowedFactory<'T> = class - inherit SeqFactory<'T,'T []> + inherit SeqComponentFactory<'T,'T []> + interface ISeqFactory<'T,'T []> new : windowSize:int -> WindowedFactory<'T> end - and ISkipping = - interface - abstract member Skipping : unit -> bool - end - - and [] SeqComponentSimple<'T,'U> = - class - inherit Consumer<'T,'U> - interface ICompletionChaining - new : next:ICompletionChaining -> SeqComponentSimple<'T,'U> - end - - and [] SeqComponentSimpleValue<'T,'U,'Value> = - class - inherit SeqComponentSimple<'T,'U> - val mutable Value : 'Value - new : next:ICompletionChaining*value:'Value -> SeqComponentSimpleValue<'T,'U,'Value> - end - and [] SeqComponent<'T,'U> = class - inherit Consumer<'T,'U> - interface ICompletionChaining - new : next:ICompletionChaining -> - SeqComponent<'T,'U> + inherit Consumer<'T,'U> + interface ICompletionChaining + new : next: ICompletionChaining -> + SeqComponent<'T,'U> + abstract member + CreateFilter : filter:('T -> bool) -> SeqComponent<'T,'U> + abstract member + CreateMap : map:('S -> 'T) -> SeqComponent<'S,'U> + abstract member Skipping : unit -> bool + override + CreateFilter : filter:('T -> bool) -> SeqComponent<'T,'U> + override CreateMap : map:('S -> 'T) -> SeqComponent<'S,'U> + override Skipping : unit -> bool end - and Choose<'T,'U,'V> = class inherit SeqComponent<'T,'V> @@ -251,6 +296,31 @@ namespace Microsoft.FSharp.Collections Except<'T,'V> override ProcessNext : input:'T -> bool end + and Filter<'T,'V> = + class + inherit SeqComponent<'T,'V> + new : filter:('T -> bool) * next: Consumer<'T,'V> -> + Filter<'T,'V> + override CreateMap : map:('S -> 'T) -> SeqComponent<'S,'V> + override ProcessNext : input:'T -> bool + end + and FilterThenMap<'T,'U,'V> = + class + inherit SeqComponent<'T,'V> + new : filter:('T -> bool) * map:('T -> 'U) * + next: Consumer<'U,'V> -> + FilterThenMap<'T,'U,'V> + override ProcessNext : input:'T -> bool + end + and Map<'T,'U,'V> = + class + inherit SeqComponent<'T,'V> + new : map:('T -> 'U) * next: Consumer<'U,'V> -> + Map<'T,'U,'V> + override + CreateFilter : filter:('T -> bool) -> SeqComponent<'T,'V> + override ProcessNext : input:'T -> bool + end and Map2First<'First,'Second,'U,'V> = class inherit SeqComponent<'First,'V> @@ -285,6 +355,21 @@ namespace Microsoft.FSharp.Collections override OnDispose : unit -> unit override ProcessNext : input:'First -> bool end + and MapThenFilter<'T,'U,'V> = + class + inherit SeqComponent<'T,'V> + new : map:('T -> 'U) * filter:('U -> bool) * + next: Consumer<'U,'V> -> + MapThenFilter<'T,'U,'V> + override ProcessNext : input:'T -> bool + end + and Mapi<'T,'U,'V> = + class + inherit SeqComponent<'T,'V> + new : mapi:(int -> 'T -> 'U) * next: Consumer<'U,'V> -> + Mapi<'T,'U,'V> + override ProcessNext : input:'T -> bool + end and Mapi2<'First,'Second,'U,'V> = class inherit SeqComponent<'First,'V> @@ -314,11 +399,11 @@ namespace Microsoft.FSharp.Collections and Skip<'T,'V> = class inherit SeqComponent<'T,'V> - interface ISkipping - new : skipCount:int * exceptionOnNotEnoughElements:(string->array->unit) * next: Consumer<'T,'V> -> + new : skipCount:int * next: Consumer<'T,'V> -> Skip<'T,'V> override OnComplete : PipeIdx -> unit override ProcessNext : input:'T -> bool + override Skipping : unit -> bool end and SkipWhile<'T,'V> = class @@ -419,7 +504,7 @@ namespace Microsoft.FSharp.Collections consumer: Consumer<'T,'U> -> unit val execute : f:((unit -> unit) -> 'a) -> - current: SeqFactory<'T,'U> -> + current: ISeqFactory<'T,'U> -> executeOn:( OutOfBand -> Consumer<'T,'U> -> unit) -> 'a when 'a :> Consumer<'U,'U> end @@ -473,7 +558,7 @@ namespace Microsoft.FSharp.Collections interface ISeq<'U> interface IEnumerable<'U> new : enumerable:IEnumerable<'T> * - current: SeqFactory<'T,'U> -> + current: ISeqFactory<'T,'U> -> Enumerable<'T,'U> end and ConcatEnumerator<'T,'Collection when 'Collection :> seq<'T>> = @@ -504,7 +589,7 @@ namespace Microsoft.FSharp.Collections end val create : enumerable:IEnumerable<'a> -> - current: SeqFactory<'a,'b> -> ISeq<'b> + current: ISeqFactory<'a,'b> -> ISeq<'b> end module EmptyEnumerable = begin type Enumerable<'T> = @@ -533,15 +618,15 @@ namespace Microsoft.FSharp.Collections interface ISeq<'U> interface IEnumerable<'U> new : delayedArray:(unit -> 'T array) * - current: SeqFactory<'T,'U> -> + current: ISeqFactory<'T,'U> -> Enumerable<'T,'U> end val createDelayed : delayedArray:(unit -> 'T array) -> - current: SeqFactory<'T,'U> -> ISeq<'U> + current: ISeqFactory<'T,'U> -> ISeq<'U> val create : array:'T array -> - current: SeqFactory<'T,'U> -> ISeq<'U> + current: ISeqFactory<'T,'U> -> ISeq<'U> val createDelayedId : delayedArray:(unit -> 'T array) -> ISeq<'T> val createId : array:'T array -> ISeq<'T> @@ -559,12 +644,12 @@ namespace Microsoft.FSharp.Collections inherit Enumerable.EnumerableBase<'U> interface ISeq<'U> interface IEnumerable<'U> - new : alist:'T list * current: SeqFactory<'T,'U> -> + new : alist:'T list * current: ISeqFactory<'T,'U> -> Enumerable<'T,'U> end val create : alist:'a list -> - current: SeqFactory<'a,'b> -> ISeq<'b> + current: ISeqFactory<'a,'b> -> ISeq<'b> end module Unfold = begin type Enumerator<'T,'U,'State> = @@ -582,7 +667,7 @@ namespace Microsoft.FSharp.Collections interface ISeq<'U> interface IEnumerable<'U> new : generator:('GeneratorState -> ('T * 'GeneratorState) option) * - state:'GeneratorState * current: SeqFactory<'T,'U> -> + state:'GeneratorState * current: ISeqFactory<'T,'U> -> Enumerable<'T,'U,'GeneratorState> end end @@ -602,7 +687,7 @@ namespace Microsoft.FSharp.Collections interface ISeq<'U> interface IEnumerable<'U> new : count:Nullable * f:(int -> 'T) * - current: SeqFactory<'T,'U> -> + current: ISeqFactory<'T,'U> -> Enumerable<'T,'U> end val upto : @@ -622,6 +707,9 @@ namespace Microsoft.FSharp.Collections val inline foreach : f:((unit -> unit) -> 'a) -> source: ISeq<'b> -> 'a when 'a :> Consumer<'b,'b> + val inline compose : + factory: ISeqFactory<'T,'a> -> + source: ISeq<'T> -> ISeq<'a> [] val empty<'T> : ISeq<'T> [] @@ -634,8 +722,6 @@ namespace Microsoft.FSharp.Collections val init : count:int -> f:(int -> 'T) -> ISeq<'T> [] val iter : f:('T -> unit) -> source: ISeq<'T> -> unit - [] - val tryHead : source: ISeq<'T> -> 'T option [] val tryItem : i:int -> source: ISeq<'T> -> 'T option [] @@ -647,24 +733,22 @@ namespace Microsoft.FSharp.Collections element:'T -> source: ISeq<'T> -> bool when 'T : equality [] val forall : f:('T -> bool) -> source: ISeq<'T> -> bool - - [] - val inline filter : f:('T -> bool) -> source: ISeq<'T> -> ISeq<'T> - - [] - val inline map : f:('T -> 'U) -> source: ISeq<'T> -> ISeq<'U> - + [] + val filter : + f:('T -> bool) -> source: ISeq<'T> -> ISeq<'T> + [] + val map : + f:('T -> 'U) -> source: ISeq<'T> -> ISeq<'U> [] - val inline mapi : f:(int->'a->'b) -> source: ISeq<'a> -> ISeq<'b> - - val mapi_adapt : f:OptimizedClosures.FSharpFunc -> source: ISeq<'a> -> ISeq<'b> - + val mapi : + f:(int -> 'a -> 'b) -> + source: ISeq<'a> -> ISeq<'b> [] - val choose : f:('a->option<'b>) -> source: ISeq<'a> -> ISeq<'b> - + val choose : + f:('a -> 'b option) -> + source: ISeq<'a> -> ISeq<'b> [] - val inline indexed : source: ISeq<'a> -> ISeq - + val indexed : source: ISeq<'a> -> ISeq [] val tryPick : f:('T -> 'U option) -> source: ISeq<'T> -> Option<'U> From 3f0cccc9a975213030f7a14587438ccb6058b8c1 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sat, 5 Nov 2016 00:59:20 +0100 Subject: [PATCH 52/59] Remove Helper from signature file Probably shouldn't be exposed in that manor in the first place, but secondly they caused a error in ci_part1. Used this as a chance to rename the module as well. Modified item/tryItem to use skip Unit tests check that the item call object the lazy nature of the Seq.init Starting the exposure of the inlinable Composer - Still hidden via internal module - simplified PipeIdx, no need for optional now - Made ISeqFactory an abstract class instead of interface so as not to require a stub implementation of PipeIdx in every object expression (or alternatively if the abstract class was used with the interface, then explicit declaration of the interface as well) - filter and map changed to inline versions Fix incorrect pipeIdx Hack to stop tail calls on ICompletionChaining passing a reference as an argument in a funciton stops the F# compiler from outputting a tail instruction for that function. None of these functions will be significantly deep as to warrant the need for a tail call. mapi to inline version - added a mapi_adapt version for non-inlined --- src/fsharp/FSharp.Core/seq.fs | 89 ++-- src/fsharp/FSharp.Core/seqcomposer.fs | 560 +++++++++++-------------- src/fsharp/FSharp.Core/seqcomposer.fsi | 260 ++++-------- 3 files changed, 367 insertions(+), 542 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index daafe8076c0..138191226d5 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -39,16 +39,12 @@ namespace Microsoft.FSharp.Collections open Microsoft.FSharp.Core.ICloneableExtensions #else #endif - let mkDelayedSeq (f: unit -> IEnumerable<'T>) = mkSeq (fun () -> f().GetEnumerator()) let inline indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) [] let toComposer (source:seq<'T>): Composer.Core.ISeq<'T> = Composer.Seq.toComposer source - - let inline foreach f (source:seq<_>) = - Composer.Seq.foreach f (toComposer source) let inline foreach f (source:seq<_>) = Composer.Seq.foreach f (toComposer source) @@ -67,7 +63,7 @@ namespace Microsoft.FSharp.Collections [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> = Composer.Seq.unfold generator state - |> Composer.Helpers.upcastEnumerable + |> Upcast.enumerable [] let empty<'T> = (EmptyEnumerable :> seq<'T>) @@ -75,12 +71,12 @@ namespace Microsoft.FSharp.Collections [] let initInfinite<'T> (f:int->'T) : IEnumerable<'T> = Composer.Seq.initInfinite f - |> Composer.Helpers.upcastEnumerable + |> Upcast.enumerable [] let init<'T> (count:int) (f:int->'T) : IEnumerable<'T> = Composer.Seq.init count f - |> Composer.Helpers.upcastEnumerable + |> Upcast.enumerable [] let iter f (source : seq<'T>) = @@ -99,25 +95,12 @@ namespace Microsoft.FSharp.Collections [] let item i (source : seq<'T>) = if i < 0 then invalidArgInputMustBeNonNegative "index" i else - source - |> foreach (fun halt -> - { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values<_,_,_> (0, false, Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - if this.Value._1 = i then - this.Value._2 <- true - this.Value._3 <- value - halt () - else - this.Value._1 <- this.Value._1 + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - override this.OnComplete _ = - if not this.Value._2 then - let index = i - this.Value._1 + 1 - invalidArgFmt "index" - "{0}\nseq was short by {1} {2}" - [|SR.GetString SR.notEnoughElements; index; (if index=1 then "element" else "elements")|] - }) - |> fun item -> item.Value._3 + source + |> seqFactory (Composer.Seq.SkipFactory (i, invalidArgumnetIndex)) + |> tryHead + |> function + | None -> invalidArgFmt "index" "{0}\nseq was short by 1 element" [|SR.GetString SR.notEnoughElements|] + | Some value -> value [] let tryItem i (source:seq<'T>) = @@ -186,18 +169,10 @@ namespace Microsoft.FSharp.Collections let revamp3 f (ie1 : seq<_>) (source2 : seq<_>) (source3 : seq<_>) = mkSeq (fun () -> f (ie1.GetEnumerator()) (source2.GetEnumerator()) (source3.GetEnumerator())) - let private seqFactory createSeqComponent (source:seq<'T>) = - checkNonNull "source" source - match source with - | :? Composer.Core.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose createSeqComponent) - | :? array<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.Seq.Array.create a createSeqComponent) - | :? list<'T> as a -> Composer.Helpers.upcastEnumerable (Composer.Seq.List.create a createSeqComponent) - | _ -> Composer.Helpers.upcastEnumerable (Composer.Seq.Enumerable.create source createSeqComponent) - [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = Composer.Seq.filter f (toComposer source) - |> Composer.Helpers.upcastEnumerable + |> Upcast.enumerable [] let where f source = filter f source @@ -205,12 +180,13 @@ namespace Microsoft.FSharp.Collections [] let map<'T,'U> (f:'T->'U) (source:seq<'T>) : seq<'U> = Composer.Seq.map f (toComposer source) - |> Composer.Helpers.upcastEnumerable + |> Upcast.enumerable [] - let mapi f source = - Composer.Seq.mapi f (toComposer source) - |> Composer.Helpers.upcastEnumerable + let mapi f source = + let f' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f + Composer.Seq.mapi_adapt f' (toComposer source) + |> Upcast.enumerable [] let mapi2 f source1 source2 = @@ -221,7 +197,7 @@ namespace Microsoft.FSharp.Collections let map2<'T,'U,'V> (f:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = checkNonNull "source1" source1 match source1 with - | :? Composer.Core.ISeq<'T> as s -> Composer.Helpers.upcastEnumerable (s.Compose (Composer.Seq.Map2FirstFactory (f, source2))) + | :? Composer.Core.ISeq<'T> as s -> Upcast.enumerable (s.Compose (Composer.Seq.Map2FirstFactory (f, source2))) | _ -> source2 |> seqFactory (Composer.Seq.Map2SecondFactory (f, source1)) [] @@ -233,12 +209,12 @@ namespace Microsoft.FSharp.Collections [] let choose f source = Composer.Seq.choose f (toComposer source) - |> Composer.Helpers.upcastEnumerable + |> Upcast.enumerable [] let indexed source = Composer.Seq.indexed (toComposer source) - |> Composer.Helpers.upcastEnumerable + |> Upcast.enumerable [] let zip source1 source2 = @@ -385,7 +361,7 @@ namespace Microsoft.FSharp.Collections checkNonNull "source2" source2 match source1 with | :? Composer.Seq.Enumerable.EnumerableBase<'T> as s -> s.Append source2 - | _ -> Composer.Helpers.upcastEnumerable (new Composer.Seq.Enumerable.AppendEnumerable<_>([source2; source1])) + | _ -> Upcast.enumerable (new Composer.Seq.Enumerable.AppendEnumerable<_>([source2; source1])) [] @@ -429,7 +405,7 @@ namespace Microsoft.FSharp.Collections [] let ofArray (source : 'T array) = checkNonNull "source" source - Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createId source) + Upcast.enumerable (Composer.Seq.Array.createId source) [] let toArray (source : seq<'T>) = @@ -679,7 +655,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceBy keyf array array - Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedSort) + Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedSort) [] let sort source = @@ -688,7 +664,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlace array array - Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedSort) + Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedSort) [] let sortWith f source = @@ -697,7 +673,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceWith f array array - Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedSort) + Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedSort) [] let inline sortByDescending keyf source = @@ -920,10 +896,6 @@ namespace Microsoft.FSharp.Collections let takeWhile p (source: seq<_>) = source |> seqFactory (Composer.Seq.TakeWhileFactory p) - [] - let skip count (source: seq<_>) = - source |> seqFactory (Composer.Seq.SkipFactory count) - [] let skipWhile p (source: seq<_>) = source |> seqFactory (Composer.Seq.SkipWhileFactory p) @@ -968,17 +940,6 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun exists -> exists.Value - [] - let tryHead (source : seq<_>) = - source - |> foreach (fun halt -> - { new Composer.Core.Folder<'T, Option<'T>> (None) with - override this.ProcessNext value = - this.Value <- Some value - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun head -> head.Value - source1 |> foreach (fun halt -> { new Composer.Core.Folder<_,bool> (false) with @@ -1059,7 +1020,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.Reverse array array - Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedReverse) + Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedReverse) [] let permute f (source:seq<_>) = @@ -1068,7 +1029,7 @@ namespace Microsoft.FSharp.Collections source |> toArray |> Array.permute f - Composer.Helpers.upcastEnumerable (Composer.Seq.Array.createDelayedId delayedPermute) + Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedPermute) [] let mapFold<'T,'State,'Result> (f: 'State -> 'T -> 'Result * 'State) acc source = diff --git a/src/fsharp/FSharp.Core/seqcomposer.fs b/src/fsharp/FSharp.Core/seqcomposer.fs index 3f36e2c1469..6ebe4e26cf8 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fs +++ b/src/fsharp/FSharp.Core/seqcomposer.fs @@ -14,21 +14,17 @@ namespace Microsoft.FSharp.Collections open Microsoft.FSharp.Control open Microsoft.FSharp.Collections open Microsoft.FSharp.Primitives.Basics - + [] module Composer = open IEnumerator module Core = - type PipeIdx = int - type ``PipeIdx?`` = Nullable - let emptyPipeIdx = Nullable () - let inline getPipeIdx (maybePipeIdx:``PipeIdx?``) = if maybePipeIdx.HasValue then maybePipeIdx.Value else 1 - let inline makePipeIdx (pipeIdx:PipeIdx) = Nullable pipeIdx + type PipeIdx = int type ICompletionChaining = - abstract OnComplete : PipeIdx -> unit - abstract OnDispose : unit -> unit + abstract OnComplete : stopTailCall:byref * PipeIdx -> unit + abstract OnDispose : stopTailCall:byref -> unit type IOutOfBand = abstract StopFurtherProcessing : PipeIdx -> unit @@ -38,16 +34,16 @@ namespace Microsoft.FSharp.Collections abstract ProcessNext : input:'T -> bool abstract OnComplete : PipeIdx -> unit - abstract OnDispose : unit -> unit + abstract OnDispose : unit -> unit default __.OnComplete _ = () default __.OnDispose () = () interface ICompletionChaining with - member this.OnComplete terminatingIdx = + member this.OnComplete (_, terminatingIdx) = this.OnComplete terminatingIdx - member this.OnDispose () = + member this.OnDispose _ = try this.OnDispose () finally () @@ -84,266 +80,209 @@ namespace Microsoft.FSharp.Collections Value = init } - type ISeqFactory<'T,'U> = + [] + type SeqFactory<'T,'U> () = abstract PipeIdx : PipeIdx - abstract Create<'V> : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> + abstract Create<'V> : IOutOfBand -> PipeIdx -> Consumer<'U,'V> -> Consumer<'T,'V> + + default __.PipeIdx = 1 + + member this.Build outOfBand next = this.Create outOfBand 1 next type ISeq<'T> = inherit IEnumerable<'T> - abstract member Compose<'U> : (ISeqFactory<'T,'U>) -> ISeq<'U> + abstract member Compose<'U> : (SeqFactory<'T,'U>) -> ISeq<'U> abstract member ForEach<'consumer when 'consumer :> Consumer<'T,'T>> : f:((unit->unit)->'consumer) -> 'consumer open Core - module internal Helpers = + module internal TailCall = // used for performance reasons; these are not recursive calls, so should be safe // ** it should be noted that potential changes to the f# compiler may render this function // ineffictive ** - let inline avoidTailCall boolean = match boolean with true -> true | false -> false + let inline avoid boolean = match boolean with true -> true | false -> false + module internal Upcast = // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality // is fixed with the compiler then these functions can be removed. - let inline upcastSeq (t:#ISeq<'T>) : ISeq<'T> = (# "" t : ISeq<'T> #) - let inline upcastFactory (t:#ISeqFactory<'T,'U>) : ISeqFactory<'T,'U> = (# "" t : ISeqFactory<'T,'U> #) - let inline upcastEnumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) - let inline upcastEnumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) - let inline upcastEnumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) - let inline upcastICompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) - - open Helpers + let inline seq (t:#ISeq<'T>) : ISeq<'T> = (# "" t : ISeq<'T> #) + let inline enumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) + let inline enumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) + let inline enumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) + let inline iCompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) module internal Seq = - type [] SeqComponentFactory<'T,'U> (pipeIdx:``PipeIdx?``) = - new() = SeqComponentFactory<'T,'U> (emptyPipeIdx) - - interface ISeqFactory<'T,'U> with - member __.PipeIdx = getPipeIdx pipeIdx - member __.Create<'V> (_:IOutOfBand) (_:``PipeIdx?``) (_:Consumer<'U,'V>) : Consumer<'T,'V> = failwith "library implementation error: Create on base factory should not be called" + type ComposedFactory<'T,'U,'V> private (first:SeqFactory<'T,'U>, second:SeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = + inherit SeqFactory<'T,'V>() - and ComposedFactory<'T,'U,'V> private (first:ISeqFactory<'T,'U>, second:ISeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = - inherit SeqComponentFactory<'T,'V> (makePipeIdx secondPipeIdx) + override __.PipeIdx = + secondPipeIdx - interface ISeqFactory<'T,'V> with - member this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'V,'W>) : Consumer<'T,'W> = - first.Create outOfBand pipeIdx (second.Create outOfBand (makePipeIdx secondPipeIdx) next) + override this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'V,'W>) : Consumer<'T,'W> = + first.Create outOfBand pipeIdx (second.Create outOfBand secondPipeIdx next) - static member Combine (first:ISeqFactory<'T,'U>) (second:ISeqFactory<'U,'V>) : ISeqFactory<'T,'V> = - ComposedFactory(first, second, first.PipeIdx+1) |> upcastFactory + static member Combine (first:SeqFactory<'T,'U>) (second:SeqFactory<'U,'V>) : SeqFactory<'T,'V> = + upcast ComposedFactory(first, second, first.PipeIdx+1) and ChooseFactory<'T,'U> (filter:'T->option<'U>) = - inherit SeqComponentFactory<'T,'U> () - interface ISeqFactory<'T,'U> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) + inherit SeqFactory<'T,'U> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) and DistinctFactory<'T when 'T: equality> () = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) - - and FilterFactory<'T> (filter:'T->bool) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = - match next with - | :? SeqComponent<'T,'V> as next -> upcast next.CreateFilter filter - | _ -> upcast Filter (filter, next) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) and IdentityFactory<'T> () = - inherit SeqComponentFactory<'T,'T> () - static let singleton = IdentityFactory<'T>() - interface ISeqFactory<'T,'T> with - member __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next + inherit SeqFactory<'T,'T> () + static let singleton : SeqFactory<'T,'T> = upcast (IdentityFactory<'T>()) + override __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next static member Instance = singleton - and MapFactory<'T,'U> (map:'T->'U) = - inherit SeqComponentFactory<'T,'U> () - interface ISeqFactory<'T,'U> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = - match next with - | :? SeqComponent<'U,'V> as next -> upcast next.CreateMap map - | _ -> upcast Map<_,_,_> (map, next) - and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = - inherit SeqComponentFactory<'First,'U> () - interface ISeqFactory<'First,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, outOfBand, next, getPipeIdx pipeIdx) + inherit SeqFactory<'First,'U> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, outOfBand, next, pipeIdx) and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = - inherit SeqComponentFactory<'Second,'U> () - interface ISeqFactory<'Second,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, outOfBand, next, getPipeIdx pipeIdx) + inherit SeqFactory<'Second,'U> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, outOfBand, next, pipeIdx) and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = - inherit SeqComponentFactory<'First,'U> () - interface ISeqFactory<'First,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, outOfBand, next, getPipeIdx pipeIdx) - - and MapiFactory<'T,'U> (mapi:int->'T->'U) = - inherit SeqComponentFactory<'T,'U> () - interface ISeqFactory<'T,'U> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Mapi (mapi, next) + inherit SeqFactory<'First,'U> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, outOfBand, next, pipeIdx) and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = - inherit SeqComponentFactory<'First,'U> () - interface ISeqFactory<'First,'U> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, outOfBand, next, getPipeIdx pipeIdx) + inherit SeqFactory<'First,'U> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, outOfBand, next, pipeIdx) and PairwiseFactory<'T> () = - inherit SeqComponentFactory<'T,'T*'T> () - interface ISeqFactory<'T,'T*'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) + inherit SeqFactory<'T,'T*'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) and ScanFactory<'T,'State> (folder:'State->'T->'State, initialState:'State) = - inherit SeqComponentFactory<'T,'State> () - interface ISeqFactory<'T,'State> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) + inherit SeqFactory<'T,'State> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) - and SkipFactory<'T> (count:int) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, next) + and SkipFactory<'T> (count:int, onNotEnoughElements) = + inherit SeqFactory<'T,'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, onNotEnoughElements, next) and SkipWhileFactory<'T> (predicate:'T->bool) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) and TakeWhileFactory<'T> (predicate:'T->bool) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, outOfBand, next, getPipeIdx pipeIdx) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, outOfBand, next, pipeIdx) and TakeFactory<'T> (count:int) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, outOfBand, next, getPipeIdx pipeIdx) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, outOfBand, next, pipeIdx) and TailFactory<'T> () = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) and TruncateFactory<'T> (count:int) = - inherit SeqComponentFactory<'T,'T> () - interface ISeqFactory<'T,'T> with - member this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:``PipeIdx?``) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, getPipeIdx pipeIdx) + inherit SeqFactory<'T,'T> () + override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, pipeIdx) and WindowedFactory<'T> (windowSize:int) = - inherit SeqComponentFactory<'T, 'T[]> () - interface ISeqFactory<'T, 'T[]> with - member this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:``PipeIdx?``) (next:Consumer<'T[],'V>) : Consumer<'T,'V> = upcast Windowed (windowSize, next) - - and [] SeqComponent<'T,'U> (next:ICompletionChaining) = - inherit Consumer<'T,'U>() + inherit SeqFactory<'T, 'T[]> () + override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T[],'V>) : Consumer<'T,'V> = upcast Windowed (windowSize, next) + and ISkipping = // Seq.init(Infinite)? lazily uses Current. The only Composer component that can do that is Skip // and it can only do it at the start of a sequence abstract Skipping : unit -> bool - abstract CreateMap<'S> : map:('S->'T) -> SeqComponent<'S,'U> - abstract CreateFilter : filter:('T->bool) -> SeqComponent<'T,'U> + and [] SeqComponentSimple<'T,'U> (next:ICompletionChaining) = + inherit Consumer<'T,'U>() interface ICompletionChaining with - member this.OnComplete terminatingIdx = - this.OnComplete terminatingIdx - next.OnComplete terminatingIdx - member this.OnDispose () = - try this.OnDispose () - finally next.OnDispose () + member this.OnComplete (stopTailCall, terminatingIdx) = + next.OnComplete (&stopTailCall, terminatingIdx) + member this.OnDispose stopTailCall = + next.OnDispose (&stopTailCall) - default __.Skipping () = false + and [] SeqComponentSimpleValue<'T,'U,'Value> = + inherit SeqComponentSimple<'T,'U> - default this.CreateMap<'S> (map:'S->'T) = upcast Map<_,_,_> (map, this) - default this.CreateFilter (filter:'T->bool) = upcast Filter (filter, this) + val mutable Value : 'Value + + new (next, init) = { + inherit SeqComponentSimple<'T,'U>(next) + Value = init + } + + and [] SeqComponent<'T,'U> (next:ICompletionChaining) = + inherit Consumer<'T,'U>() + + interface ICompletionChaining with + member this.OnComplete (stopTailCall, terminatingIdx) = + this.OnComplete terminatingIdx + next.OnComplete (&stopTailCall, terminatingIdx) + member this.OnDispose stopTailCall = + try this.OnDispose () + finally next.OnDispose (&stopTailCall) and Choose<'T,'U,'V> (choose:'T->option<'U>, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) override __.ProcessNext (input:'T) : bool = match choose input with - | Some value -> avoidTailCall (next.ProcessNext value) + | Some value -> TailCall.avoid (next.ProcessNext value) | None -> false and Distinct<'T,'V when 'T: equality> (next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) override __.ProcessNext (input:'T) : bool = if hashSet.Add input then - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) else false and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) override __.ProcessNext (input:'T) : bool = if hashSet.Add(keyFunction input) then - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) else false and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) override __.ProcessNext (input:'T) : bool = if cached.Value.Add input then - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) else false - and Filter<'T,'V> (filter:'T->bool, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) - - override this.CreateMap<'S> (map:'S->'T) = upcast MapThenFilter<_,_,_> (map, filter, next) - - override __.ProcessNext (input:'T) : bool = - if filter input then - avoidTailCall (next.ProcessNext input) - else - false - - and FilterThenMap<'T,'U,'V> (filter:'T->bool, map:'T->'U, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - if filter input then - avoidTailCall (next.ProcessNext (map input)) - else - false - - and Map<'T,'U,'V> (map:'T->'U, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override this.CreateFilter (filter:'T->bool) = upcast FilterThenMap (filter, map, next) - - override __.ProcessNext (input:'T) : bool = - avoidTailCall (next.ProcessNext (map input)) - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(next) + inherit SeqComponent<'First,'V>(Upcast.iCompletionChaining next) let input2 = enumerable2.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map override __.ProcessNext (input:'First) : bool = if input2.MoveNext () then - avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current))) + TailCall.avoid (next.ProcessNext (map'.Invoke (input, input2.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -352,14 +291,14 @@ namespace Microsoft.FSharp.Collections input2.Dispose () and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'Second,'V>(next) + inherit SeqComponent<'Second,'V>(Upcast.iCompletionChaining next) let input1 = enumerable1.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map override __.ProcessNext (input:'Second) : bool = if input1.MoveNext () then - avoidTailCall (next.ProcessNext (map'.Invoke (input1.Current, input))) + TailCall.avoid (next.ProcessNext (map'.Invoke (input1.Current, input))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -368,7 +307,7 @@ namespace Microsoft.FSharp.Collections input1.Dispose () and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(next) + inherit SeqComponent<'First,'V>(Upcast.iCompletionChaining next) let input2 = enumerable2.GetEnumerator () let input3 = enumerable3.GetEnumerator () @@ -376,7 +315,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'First) : bool = if input2.MoveNext () && input3.MoveNext () then - avoidTailCall (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) + TailCall.avoid (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -385,28 +324,8 @@ namespace Microsoft.FSharp.Collections try input2.Dispose () finally input3.Dispose () - and MapThenFilter<'T,'U,'V> (map:'T->'U, filter:'U->bool, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - override __.ProcessNext (input:'T) : bool = - let u = map input - if filter u then - avoidTailCall (next.ProcessNext u) - else - false - - and Mapi<'T,'U,'V> (mapi:int->'T->'U, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(next) - - let mutable idx = 0 - let mapi' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt mapi - - override __.ProcessNext (input:'T) : bool = - idx <- idx + 1 - avoidTailCall (next.ProcessNext (mapi'.Invoke (idx-1, input))) - and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(next) + inherit SeqComponent<'First,'V>(Upcast.iCompletionChaining next) let mutable idx = 0 let input2 = enumerable2.GetEnumerator () @@ -415,7 +334,7 @@ namespace Microsoft.FSharp.Collections override __.ProcessNext (input:'First) : bool = if input2.MoveNext () then idx <- idx + 1 - avoidTailCall (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) + TailCall.avoid (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) else outOfBand.StopFurtherProcessing pipeIdx false @@ -424,7 +343,7 @@ namespace Microsoft.FSharp.Collections input2.Dispose () and Pairwise<'T,'V> (next:Consumer<'T*'T,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let mutable isFirst = true let mutable lastValue = Unchecked.defaultof<'T> @@ -437,45 +356,46 @@ namespace Microsoft.FSharp.Collections else let currentPair = lastValue, input lastValue <- input - avoidTailCall (next.ProcessNext currentPair) + TailCall.avoid (next.ProcessNext currentPair) and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:Consumer<'State,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder let mutable foldResult = initialState override __.ProcessNext (input:'T) : bool = foldResult <- f.Invoke(foldResult, input) - avoidTailCall (next.ProcessNext foldResult) + TailCall.avoid (next.ProcessNext foldResult) - and Skip<'T,'V> (skipCount:int, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + and Skip<'T,'V> (skipCount:int, notEnoughElements:string->array->unit, next:Consumer<'T,'V>) = + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let mutable count = 0 - override __.Skipping () = - if count < skipCount then - count <- count + 1 - true - else - false + interface ISkipping with + member __.Skipping () = + if count < skipCount then + count <- count + 1 + true + else + false override __.ProcessNext (input:'T) : bool = if count < skipCount then count <- count + 1 false else - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) override __.OnComplete _ = if count < skipCount then let x = skipCount - count - invalidOpFmt "tried to skip {0} {1} past the end of the seq" + notEnoughElements "{0}\ntried to skip {1} {2} past the end of the seq" [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] and SkipWhile<'T,'V> (predicate:'T->bool, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let mutable skip = true @@ -485,9 +405,9 @@ namespace Microsoft.FSharp.Collections if skip then false else - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) else - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) and Take<'T,'V> (takeCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipelineIdx:int) = inherit Truncate<'T, 'V>(takeCount, outOfBand, next, pipelineIdx) @@ -499,17 +419,17 @@ namespace Microsoft.FSharp.Collections [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] and TakeWhile<'T,'V> (predicate:'T->bool, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) override __.ProcessNext (input:'T) : bool = if predicate input then - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) else outOfBand.StopFurtherProcessing pipeIdx false and Tail<'T, 'V> (next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let mutable first = true @@ -518,14 +438,14 @@ namespace Microsoft.FSharp.Collections first <- false false else - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) override this.OnComplete _ = if first then invalidArg "source" (SR.GetString(SR.notEnoughElements)) and Truncate<'T,'V> (truncateCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let mutable count = 0 @@ -536,13 +456,13 @@ namespace Microsoft.FSharp.Collections count <- count + 1 if count = truncateCount then outOfBand.StopFurtherProcessing pipeIdx - avoidTailCall (next.ProcessNext input) + TailCall.avoid (next.ProcessNext input) else outOfBand.StopFurtherProcessing pipeIdx false and Windowed<'T,'V> (windowSize: int, next:Consumer<'T[],'V>) = - inherit SeqComponent<'T,'V>(next) + inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) let circularBuffer = Array.zeroCreateUnchecked windowSize let mutable idx = 0 @@ -562,12 +482,12 @@ namespace Microsoft.FSharp.Collections else if windowSize < 32 then let window = Array.init windowSize (fun i -> circularBuffer.[(idx+i) % windowSize]) - avoidTailCall (next.ProcessNext window) + TailCall.avoid (next.ProcessNext window) else let window = Array.zeroCreateUnchecked windowSize Array.Copy(circularBuffer, idx, window, 0, windowSize - idx) Array.Copy(circularBuffer, 0, window, windowSize - idx, idx) - avoidTailCall (next.ProcessNext window) + TailCall.avoid (next.ProcessNext window) type SeqProcessNextStates = | InProcess = 0 @@ -629,8 +549,8 @@ namespace Microsoft.FSharp.Collections iterate state let makeIsSkipping (consumer:Consumer<'T,'U>) = - match consumer with - | :? SeqComponent<'T,'U> as c -> c.Skipping + match box consumer with + | :? ISkipping as skip -> skip.Skipping | _ -> fun () -> false let init f (terminatingIdx:int) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = @@ -641,21 +561,23 @@ namespace Microsoft.FSharp.Collections if maybeSkipping then maybeSkipping <- isSkipping () - if (not maybeSkipping) then + if not maybeSkipping then consumer.ProcessNext (f (idx+1)) |> ignore idx <- idx + 1 - let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:ISeqFactory<'T,'U>) executeOn = + let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:SeqFactory<'T,'U>) executeOn = let pipeline = OutOfBand() let result = f (fun () -> (pipeline:>IOutOfBand).StopFurtherProcessing (current.PipeIdx+1)) - let consumer = current.Create pipeline emptyPipeIdx result + let consumer = current.Build pipeline result try executeOn pipeline consumer - (upcastICompletionChaining consumer).OnComplete pipeline.HaltedIdx + let mutable stopTailCall = () + (Upcast.iCompletionChaining consumer).OnComplete (&stopTailCall, pipeline.HaltedIdx) result finally - (upcastICompletionChaining consumer).OnDispose () + let mutable stopTailCall = () + (Upcast.iCompletionChaining consumer).OnDispose (&stopTailCall) module Enumerable = type Empty<'T>() = @@ -677,10 +599,11 @@ namespace Microsoft.FSharp.Collections type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ICompletionChaining) = interface IDisposable with member __.Dispose() : unit = - seqComponent.OnDispose () + let mutable stopTailCall = () + seqComponent.OnDispose (&stopTailCall) interface IEnumerator with - member this.Current : obj = box ((upcastEnumerator this)).Current + member this.Current : obj = box ((Upcast.enumerator this)).Current member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)" member __.Reset () : unit = noReset () @@ -699,13 +622,13 @@ namespace Microsoft.FSharp.Collections abstract member Append : (seq<'T>) -> IEnumerable<'T> - default this.Append source = upcastEnumerable (AppendEnumerable [this; source]) + default this.Append source = Upcast.enumerable (AppendEnumerable [this; source]) interface IEnumerable with member this.GetEnumerator () : IEnumerator = - let genericEnumerable = upcastEnumerable this + let genericEnumerable = Upcast.enumerable this let genericEnumerator = genericEnumerable.GetEnumerator () - upcastEnumeratorNonGeneric genericEnumerator + Upcast.enumeratorNonGeneric genericEnumerator interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement () @@ -725,7 +648,8 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + let mutable stopTailCall = () + (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -738,19 +662,20 @@ namespace Microsoft.FSharp.Collections try source.Dispose () finally - (upcastICompletionChaining seqComponent).OnDispose () + let mutable stopTailCall = () + (Upcast.iCompletionChaining seqComponent).OnDispose (&stopTailCall) - and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:ISeqFactory<'T,'U>) = + and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqFactory<'T,'U>) = inherit EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Create result emptyPipeIdx (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Build result (SetResult<'U> result), result)) interface ISeq<'U> with - member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) + member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.enumerable enumerable) @@ -782,7 +707,7 @@ namespace Microsoft.FSharp.Collections | _ -> failwith "library implementation error: all states should have been handled" interface IEnumerator with - member this.Current = box ((upcastEnumerator this)).Current + member this.Current = box ((Upcast.enumerator this)).Current member __.MoveNext () = state <- SeqProcessNextStates.InProcess moveNext () @@ -798,14 +723,14 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = - upcastEnumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) + Upcast.enumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) override this.Append source = - upcastEnumerable (AppendEnumerable (source :: sources)) + Upcast.enumerable (AppendEnumerable (source :: sources)) interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable<'T,'V>(this, next)) + member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) @@ -815,17 +740,17 @@ namespace Microsoft.FSharp.Collections interface IEnumerable<'T> with member this.GetEnumerator () : IEnumerator<'T> = - upcastEnumerator (new ConcatEnumerator<_,_> (sources)) + Upcast.enumerator (new ConcatEnumerator<_,_> (sources)) interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable<'T,'V>(this, next)) + member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) let create enumerable current = - upcastSeq (Enumerable(enumerable, current)) + Upcast.seq (Enumerable(enumerable, current)) module EmptyEnumerable = type Enumerable<'T> () = @@ -838,11 +763,11 @@ namespace Microsoft.FSharp.Collections member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>() override this.Append source = - upcastEnumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) + Upcast.enumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable.Enumerable<'T,'V>(this, next)) + member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable.Enumerable<'T,'V>(this, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) @@ -873,7 +798,8 @@ namespace Microsoft.FSharp.Collections moveNext () else result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + let mutable stopTailCall = () + (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -881,25 +807,25 @@ namespace Microsoft.FSharp.Collections initMoveNext () moveNext () - type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:ISeqFactory<'T,'U>) = + type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(delayedArray, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U>(delayedArray, current.Build result (SetResult<'U> result), result)) interface ISeq<'U> with - member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) + member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.array (delayedArray ())) - let createDelayed (delayedArray:unit->array<'T>) (current:ISeqFactory<'T,'U>) = - upcastSeq (Enumerable(delayedArray, current)) + let createDelayed (delayedArray:unit->array<'T>) (current:SeqFactory<'T,'U>) = + Upcast.seq (Enumerable(delayedArray, current)) - let create (array:array<'T>) (current:ISeqFactory<'T,'U>) = + let create (array:array<'T>) (current:SeqFactory<'T,'U>) = createDelayed (fun () -> array) current let createDelayedId (delayedArray:unit -> array<'T>) = @@ -924,7 +850,8 @@ namespace Microsoft.FSharp.Collections moveNext tail | _ -> result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + let mutable stopTailCall = () + (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -932,23 +859,23 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext list - type Enumerable<'T,'U>(alist:list<'T>, current:ISeqFactory<'T,'U>) = + type Enumerable<'T,'U>(alist:list<'T>, current:SeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(alist, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U>(alist, current.Build result (SetResult<'U> result), result)) interface ISeq<'U> with - member __.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) + member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.list alist) let create alist current = - upcastSeq (Enumerable(alist, current)) + Upcast.seq (Enumerable(alist, current)) module Unfold = type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, result:Result<'U>) = @@ -971,17 +898,17 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext () - type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:ISeqFactory<'T,'U>) = + type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Build result (SetResult<'U> result), result)) interface ISeq<'U> with - member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + member this.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = ForEach.execute f current (ForEach.unfold generator state) @@ -1037,7 +964,8 @@ namespace Microsoft.FSharp.Collections raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) else result.SeqState <- SeqProcessNextStates.Finished - (upcastICompletionChaining seqComponent).OnComplete result.HaltedIdx + let mutable stopTailCall = () + (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -1045,17 +973,17 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext () - type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:ISeqFactory<'T,'U>) = + type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqFactory<'T,'U>) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - upcastEnumerator (new Enumerator<'T,'U>(count, f, current.Create result emptyPipeIdx (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U>(count, f, current.Build result (SetResult<'U> result), result)) interface ISeq<'U> with - member this.Compose (next:ISeqFactory<'U,'V>) : ISeq<'V> = - upcastSeq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + member this.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) member this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = let terminatingIdx = getTerminatingIdx count @@ -1122,25 +1050,25 @@ namespace Microsoft.FSharp.Collections upto (if count.HasValue then Some (count.Value-1) else None) f interface ISeq<'T> with - member this.Compose (next:ISeqFactory<'T,'U>) : ISeq<'U> = - upcastSeq (Enumerable<'T,'V>(count, f, next)) + member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable<'T,'V>(count, f, next)) member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (upcastEnumerable this)) + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (Upcast.enumerable this)) [] let toComposer (source:seq<'T>) : ISeq<'T> = - checkNonNull "source" source match source with | :? ISeq<'T> as s -> s - | :? array<'T> as a -> upcastSeq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) - | :? list<'T> as a -> upcastSeq (List.Enumerable(a, IdentityFactory.Instance)) - | _ -> upcastSeq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) + | :? array<'T> as a -> Upcast.seq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) + | :? list<'T> as a -> Upcast.seq (List.Enumerable(a, IdentityFactory.Instance)) + | null -> nullArg "source" + | _ -> Upcast.seq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) let inline foreach f (source:ISeq<_>) = source.ForEach f - let inline compose factory (source:ISeq<'T>) = + let inline compose (factory:#SeqFactory<_,_>) (source:ISeq<'T>) = source.Compose factory [] @@ -1148,17 +1076,17 @@ namespace Microsoft.FSharp.Collections [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> = - upcastSeq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) + Upcast.seq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) [] let initInfinite<'T> (f:int->'T) : ISeq<'T> = - upcastSeq (new Init.EnumerableDecider<'T>(Nullable (), f)) + Upcast.seq (new Init.EnumerableDecider<'T>(Nullable (), f)) [] let init<'T> (count:int) (f:int->'T) : ISeq<'T> = if count < 0 then invalidArgInputMustBeNonNegative "count" count elif count = 0 then empty else - upcastSeq (new Init.EnumerableDecider<'T>(Nullable count, f)) + Upcast.seq (new Init.EnumerableDecider<'T>(Nullable count, f)) [] let iter f (source:ISeq<'T>) = @@ -1170,20 +1098,22 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> ignore - [] - let tryItem i (source:ISeq<'T>) = - if i < 0 then None else - source + [] + let tryHead (source:ISeq<'T>) = + source |> foreach (fun halt -> - { new Folder<'T, Values>> (Values<_,_> (0, None)) with + { new Folder<'T, Option<'T>> (None) with override this.ProcessNext value = - if this.Value._1 = i then - this.Value._2 <- Some value - halt () - else - this.Value._1 <- this.Value._1 + 1 + this.Value <- Some value + halt () Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun item -> item.Value._2 + |> fun head -> head.Value + + [] + let tryItem i (source:ISeq<'T>) = + if i < 0 then None else + source.Compose (SkipFactory(i, fun _ _ -> ())) + |> tryHead [] let iteri f (source:ISeq<'T>) = @@ -1233,21 +1163,40 @@ namespace Microsoft.FSharp.Collections halt () Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun forall -> forall.Value - + [] - let filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = - source - |> compose (FilterFactory f) + let inline filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { new SeqComponentSimple<'T,'V>(Upcast.iCompletionChaining next) with + member __.ProcessNext input = + if f input then TailCall.avoid (next.ProcessNext input) + else false } } [] - let map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = - source - |> compose (MapFactory f) + let inline map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = + source |> compose { new SeqFactory<'T,'U>() with + member __.Create _ _ next = + upcast { new SeqComponentSimple<'T,'V>(Upcast.iCompletionChaining next) with + member __.ProcessNext input = + TailCall.avoid (next.ProcessNext (f input)) } } [] - let mapi f source = - source - |> compose (MapiFactory f) + let inline mapi f source = + source |> compose { new SeqFactory<'T,'U>() with + member __.Create _ _ next = + upcast { new SeqComponentSimpleValue<'T,'V,int>(Upcast.iCompletionChaining next, -1) with + override this.ProcessNext (input:'T) : bool = + this.Value <- this.Value + 1 + TailCall.avoid (next.ProcessNext (f this.Value input)) } } + + let mapi_adapt (f:OptimizedClosures.FSharpFunc<_,_,_>) source = + source |> compose { new SeqFactory<'T,'U>() with + member __.Create _ _ next = + upcast { new SeqComponentSimpleValue<'T,'V,int>(Upcast.iCompletionChaining next, -1) with + override this.ProcessNext (input:'T) : bool = + this.Value <- this.Value + 1 + TailCall.avoid (next.ProcessNext (f.Invoke (this.Value, input))) } } [] let choose f source = @@ -1255,9 +1204,8 @@ namespace Microsoft.FSharp.Collections |> compose (ChooseFactory f) [] - let indexed source = - source - |> compose (MapiFactory (fun i x -> i,x)) + let inline indexed source = + mapi (fun i x -> i,x) source [] let tryPick f (source:ISeq<'T>) = diff --git a/src/fsharp/FSharp.Core/seqcomposer.fsi b/src/fsharp/FSharp.Core/seqcomposer.fsi index 838cee6da37..c9bdf2fdb3e 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fsi +++ b/src/fsharp/FSharp.Core/seqcomposer.fsi @@ -14,7 +14,6 @@ namespace Microsoft.FSharp.Collections /// PipeIdx denotes the index of the element within the pipeline. 0 denotes the /// source of the chain. type PipeIdx = int - type ``PipeIdx?`` = Nullable /// ICompletionChaining is used to correctly handle cleaning up of the pipeline. A /// base implementation is provided in Consumer, and should not be overwritten. Consumer @@ -26,10 +25,10 @@ namespace Microsoft.FSharp.Collections /// operation which didn't have a source at least as large as was required). It is /// not called in the case of an exception being thrown whilst the stream is still /// being processed. - abstract OnComplete : PipeIdx -> unit + abstract OnComplete : stopTailCall:byref*PipeIdx -> unit /// OnDispose is used to cleanup the stream. It is always called at the last operation /// after the enumeration has completed. - abstract OnDispose : unit -> unit + abstract OnDispose : stopTailCall:byref -> unit type IOutOfBand = abstract StopFurtherProcessing : PipeIdx -> unit @@ -71,204 +70,160 @@ namespace Microsoft.FSharp.Collections new : init:'U -> Folder<'T,'U> val mutable Value: 'U - type ISeqFactory<'T,'U> = - abstract member Create : IOutOfBand -> ``PipeIdx?`` -> Consumer<'U,'V> -> Consumer<'T,'V> - abstract member PipeIdx : PipeIdx + [] + type SeqFactory<'T,'U> = + new : unit -> SeqFactory<'T,'U> + abstract PipeIdx : PipeIdx + abstract member Create : IOutOfBand -> PipeIdx -> Consumer<'U,'V> -> Consumer<'T,'V> type ISeq<'T> = inherit System.Collections.Generic.IEnumerable<'T> - abstract member Compose : ISeqFactory<'T,'U> -> ISeq<'U> + abstract member Compose : SeqFactory<'T,'U> -> ISeq<'U> abstract member ForEach : f:((unit -> unit) -> 'a) -> 'a when 'a :> Consumer<'T,'T> open Core - module internal Helpers = - val inline avoidTailCall : boolean:bool -> bool - val inline upcastSeq : t: #ISeq<'T> -> ISeq<'T> - val inline upcastFactory : - t: #ISeqFactory<'T,'U> -> ISeqFactory<'T,'U> - val inline upcastEnumerable : t:#IEnumerable<'T> -> IEnumerable<'T> - val inline upcastEnumerator : t:#IEnumerator<'T> ->IEnumerator<'T> - val inline upcastEnumeratorNonGeneric : - t:#IEnumerator -> IEnumerator - val inline upcastICompletionChaining : - t: #ICompletionChaining -> ICompletionChaining - module internal Seq = - [] - type SeqComponentFactory<'T,'U> = + type ComposedFactory<'T,'U,'V> = class - interface ISeqFactory<'T,'U> - new : unit -> SeqComponentFactory<'T,'U> - new : pipeIdx: ``PipeIdx?`` -> - SeqComponentFactory<'T,'U> - end - and ComposedFactory<'T,'U,'V> = - class - inherit SeqComponentFactory<'T,'V> - interface ISeqFactory<'T,'V> - private new : first: ISeqFactory<'T,'U> * - second: ISeqFactory<'U,'V> * + inherit SeqFactory<'T,'V> + private new : first: SeqFactory<'T,'U> * + second: SeqFactory<'U,'V> * secondPipeIdx: PipeIdx -> ComposedFactory<'T,'U,'V> static member - Combine : first: ISeqFactory<'T,'U> -> - second: ISeqFactory<'U,'V> -> - ISeqFactory<'T,'V> + Combine : first: SeqFactory<'T,'U> -> + second: SeqFactory<'U,'V> -> + SeqFactory<'T,'V> end and ChooseFactory<'T,'U> = class - inherit SeqComponentFactory<'T,'U> - interface ISeqFactory<'T,'U> + inherit SeqFactory<'T,'U> new : filter:('T -> 'U option) -> ChooseFactory<'T,'U> end and DistinctFactory<'T when 'T : equality> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : unit -> DistinctFactory<'T> end and DistinctByFactory<'T,'Key when 'Key : equality> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : keyFunction:('T -> 'Key) -> DistinctByFactory<'T,'Key> end and ExceptFactory<'T when 'T : equality> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : itemsToExclude:seq<'T> -> ExceptFactory<'T> end - and FilterFactory<'T> = - class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> - new : filter:('T -> bool) -> FilterFactory<'T> - end and IdentityFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : unit -> IdentityFactory<'T> - static member Instance : IdentityFactory<'T> - end - and MapFactory<'T,'U> = - class - inherit SeqComponentFactory<'T,'U> - interface ISeqFactory<'T,'U> - new : map:('T -> 'U) -> MapFactory<'T,'U> + static member Instance : SeqFactory<'T,'T> end and Map2FirstFactory<'First,'Second,'U> = class - inherit SeqComponentFactory<'First,'U> - interface ISeqFactory<'First,'U> + inherit SeqFactory<'First,'U> new : map:('First -> 'Second -> 'U) * input2:IEnumerable<'Second> -> Map2FirstFactory<'First,'Second,'U> end and Map2SecondFactory<'First,'Second,'U> = class - inherit SeqComponentFactory<'Second,'U> - interface ISeqFactory<'Second,'U> + inherit SeqFactory<'Second,'U> new : map:('First -> 'Second -> 'U) * input1:IEnumerable<'First> -> Map2SecondFactory<'First,'Second,'U> end and Map3Factory<'First,'Second,'Third,'U> = class - inherit SeqComponentFactory<'First,'U> - interface ISeqFactory<'First,'U> + inherit SeqFactory<'First,'U> new : map:('First -> 'Second -> 'Third -> 'U) * input2:IEnumerable<'Second> * input3:IEnumerable<'Third> -> Map3Factory<'First,'Second,'Third,'U> end - and MapiFactory<'T,'U> = - class - inherit SeqComponentFactory<'T,'U> - interface ISeqFactory<'T,'U> - new : mapi:(int -> 'T -> 'U) -> MapiFactory<'T,'U> - end and Mapi2Factory<'First,'Second,'U> = class - inherit SeqComponentFactory<'First,'U> - interface ISeqFactory<'First,'U> + inherit SeqFactory<'First,'U> new : map:(int -> 'First -> 'Second -> 'U) * input2:IEnumerable<'Second> -> Mapi2Factory<'First,'Second,'U> end and PairwiseFactory<'T> = class - inherit SeqComponentFactory<'T,('T * 'T)> - interface ISeqFactory<'T,('T * 'T)> + inherit SeqFactory<'T,('T * 'T)> new : unit -> PairwiseFactory<'T> end and ScanFactory<'T,'State> = class - inherit SeqComponentFactory<'T,'State> - interface ISeqFactory<'T,'State> + inherit SeqFactory<'T,'State> new : folder:('State -> 'T -> 'State) * initialState:'State -> ScanFactory<'T,'State> end and SkipFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> - new : count:int -> SkipFactory<'T> + inherit SeqFactory<'T,'T> + new : count:int * notEnoughElements:(string->array->unit) -> SkipFactory<'T> end and SkipWhileFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : predicate:('T -> bool) -> SkipWhileFactory<'T> end and TakeWhileFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : predicate:('T -> bool) -> TakeWhileFactory<'T> end and TakeFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : count:int -> TakeFactory<'T> end and TailFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : unit -> TailFactory<'T> end and TruncateFactory<'T> = class - inherit SeqComponentFactory<'T,'T> - interface ISeqFactory<'T,'T> + inherit SeqFactory<'T,'T> new : count:int -> TruncateFactory<'T> end and WindowedFactory<'T> = class - inherit SeqComponentFactory<'T,'T []> - interface ISeqFactory<'T,'T []> + inherit SeqFactory<'T,'T []> new : windowSize:int -> WindowedFactory<'T> end + and ISkipping = + interface + abstract member Skipping : unit -> bool + end + + and [] SeqComponentSimple<'T,'U> = + class + inherit Consumer<'T,'U> + interface ICompletionChaining + new : next:ICompletionChaining -> SeqComponentSimple<'T,'U> + end + + and [] SeqComponentSimpleValue<'T,'U,'Value> = + class + inherit SeqComponentSimple<'T,'U> + val mutable Value : 'Value + new : next:ICompletionChaining*value:'Value -> SeqComponentSimpleValue<'T,'U,'Value> + end + and [] SeqComponent<'T,'U> = class - inherit Consumer<'T,'U> - interface ICompletionChaining - new : next: ICompletionChaining -> - SeqComponent<'T,'U> - abstract member - CreateFilter : filter:('T -> bool) -> SeqComponent<'T,'U> - abstract member - CreateMap : map:('S -> 'T) -> SeqComponent<'S,'U> - abstract member Skipping : unit -> bool - override - CreateFilter : filter:('T -> bool) -> SeqComponent<'T,'U> - override CreateMap : map:('S -> 'T) -> SeqComponent<'S,'U> - override Skipping : unit -> bool + inherit Consumer<'T,'U> + interface ICompletionChaining + new : next:ICompletionChaining -> + SeqComponent<'T,'U> end + and Choose<'T,'U,'V> = class inherit SeqComponent<'T,'V> @@ -296,31 +251,6 @@ namespace Microsoft.FSharp.Collections Except<'T,'V> override ProcessNext : input:'T -> bool end - and Filter<'T,'V> = - class - inherit SeqComponent<'T,'V> - new : filter:('T -> bool) * next: Consumer<'T,'V> -> - Filter<'T,'V> - override CreateMap : map:('S -> 'T) -> SeqComponent<'S,'V> - override ProcessNext : input:'T -> bool - end - and FilterThenMap<'T,'U,'V> = - class - inherit SeqComponent<'T,'V> - new : filter:('T -> bool) * map:('T -> 'U) * - next: Consumer<'U,'V> -> - FilterThenMap<'T,'U,'V> - override ProcessNext : input:'T -> bool - end - and Map<'T,'U,'V> = - class - inherit SeqComponent<'T,'V> - new : map:('T -> 'U) * next: Consumer<'U,'V> -> - Map<'T,'U,'V> - override - CreateFilter : filter:('T -> bool) -> SeqComponent<'T,'V> - override ProcessNext : input:'T -> bool - end and Map2First<'First,'Second,'U,'V> = class inherit SeqComponent<'First,'V> @@ -355,21 +285,6 @@ namespace Microsoft.FSharp.Collections override OnDispose : unit -> unit override ProcessNext : input:'First -> bool end - and MapThenFilter<'T,'U,'V> = - class - inherit SeqComponent<'T,'V> - new : map:('T -> 'U) * filter:('U -> bool) * - next: Consumer<'U,'V> -> - MapThenFilter<'T,'U,'V> - override ProcessNext : input:'T -> bool - end - and Mapi<'T,'U,'V> = - class - inherit SeqComponent<'T,'V> - new : mapi:(int -> 'T -> 'U) * next: Consumer<'U,'V> -> - Mapi<'T,'U,'V> - override ProcessNext : input:'T -> bool - end and Mapi2<'First,'Second,'U,'V> = class inherit SeqComponent<'First,'V> @@ -399,11 +314,11 @@ namespace Microsoft.FSharp.Collections and Skip<'T,'V> = class inherit SeqComponent<'T,'V> - new : skipCount:int * next: Consumer<'T,'V> -> + interface ISkipping + new : skipCount:int * exceptionOnNotEnoughElements:(string->array->unit) * next: Consumer<'T,'V> -> Skip<'T,'V> override OnComplete : PipeIdx -> unit override ProcessNext : input:'T -> bool - override Skipping : unit -> bool end and SkipWhile<'T,'V> = class @@ -504,7 +419,7 @@ namespace Microsoft.FSharp.Collections consumer: Consumer<'T,'U> -> unit val execute : f:((unit -> unit) -> 'a) -> - current: ISeqFactory<'T,'U> -> + current: SeqFactory<'T,'U> -> executeOn:( OutOfBand -> Consumer<'T,'U> -> unit) -> 'a when 'a :> Consumer<'U,'U> end @@ -558,7 +473,7 @@ namespace Microsoft.FSharp.Collections interface ISeq<'U> interface IEnumerable<'U> new : enumerable:IEnumerable<'T> * - current: ISeqFactory<'T,'U> -> + current: SeqFactory<'T,'U> -> Enumerable<'T,'U> end and ConcatEnumerator<'T,'Collection when 'Collection :> seq<'T>> = @@ -589,7 +504,7 @@ namespace Microsoft.FSharp.Collections end val create : enumerable:IEnumerable<'a> -> - current: ISeqFactory<'a,'b> -> ISeq<'b> + current: SeqFactory<'a,'b> -> ISeq<'b> end module EmptyEnumerable = begin type Enumerable<'T> = @@ -618,15 +533,15 @@ namespace Microsoft.FSharp.Collections interface ISeq<'U> interface IEnumerable<'U> new : delayedArray:(unit -> 'T array) * - current: ISeqFactory<'T,'U> -> + current: SeqFactory<'T,'U> -> Enumerable<'T,'U> end val createDelayed : delayedArray:(unit -> 'T array) -> - current: ISeqFactory<'T,'U> -> ISeq<'U> + current: SeqFactory<'T,'U> -> ISeq<'U> val create : array:'T array -> - current: ISeqFactory<'T,'U> -> ISeq<'U> + current: SeqFactory<'T,'U> -> ISeq<'U> val createDelayedId : delayedArray:(unit -> 'T array) -> ISeq<'T> val createId : array:'T array -> ISeq<'T> @@ -644,12 +559,12 @@ namespace Microsoft.FSharp.Collections inherit Enumerable.EnumerableBase<'U> interface ISeq<'U> interface IEnumerable<'U> - new : alist:'T list * current: ISeqFactory<'T,'U> -> + new : alist:'T list * current: SeqFactory<'T,'U> -> Enumerable<'T,'U> end val create : alist:'a list -> - current: ISeqFactory<'a,'b> -> ISeq<'b> + current: SeqFactory<'a,'b> -> ISeq<'b> end module Unfold = begin type Enumerator<'T,'U,'State> = @@ -667,7 +582,7 @@ namespace Microsoft.FSharp.Collections interface ISeq<'U> interface IEnumerable<'U> new : generator:('GeneratorState -> ('T * 'GeneratorState) option) * - state:'GeneratorState * current: ISeqFactory<'T,'U> -> + state:'GeneratorState * current: SeqFactory<'T,'U> -> Enumerable<'T,'U,'GeneratorState> end end @@ -687,7 +602,7 @@ namespace Microsoft.FSharp.Collections interface ISeq<'U> interface IEnumerable<'U> new : count:Nullable * f:(int -> 'T) * - current: ISeqFactory<'T,'U> -> + current: SeqFactory<'T,'U> -> Enumerable<'T,'U> end val upto : @@ -707,9 +622,6 @@ namespace Microsoft.FSharp.Collections val inline foreach : f:((unit -> unit) -> 'a) -> source: ISeq<'b> -> 'a when 'a :> Consumer<'b,'b> - val inline compose : - factory: ISeqFactory<'T,'a> -> - source: ISeq<'T> -> ISeq<'a> [] val empty<'T> : ISeq<'T> [] @@ -722,6 +634,8 @@ namespace Microsoft.FSharp.Collections val init : count:int -> f:(int -> 'T) -> ISeq<'T> [] val iter : f:('T -> unit) -> source: ISeq<'T> -> unit + [] + val tryHead : source: ISeq<'T> -> 'T option [] val tryItem : i:int -> source: ISeq<'T> -> 'T option [] @@ -733,22 +647,24 @@ namespace Microsoft.FSharp.Collections element:'T -> source: ISeq<'T> -> bool when 'T : equality [] val forall : f:('T -> bool) -> source: ISeq<'T> -> bool - [] - val filter : - f:('T -> bool) -> source: ISeq<'T> -> ISeq<'T> - [] - val map : - f:('T -> 'U) -> source: ISeq<'T> -> ISeq<'U> + + [] + val inline filter : f:('T -> bool) -> source: ISeq<'T> -> ISeq<'T> + + [] + val inline map : f:('T -> 'U) -> source: ISeq<'T> -> ISeq<'U> + [] - val mapi : - f:(int -> 'a -> 'b) -> - source: ISeq<'a> -> ISeq<'b> + val inline mapi : f:(int->'a->'b) -> source: ISeq<'a> -> ISeq<'b> + + val mapi_adapt : f:OptimizedClosures.FSharpFunc -> source: ISeq<'a> -> ISeq<'b> + [] - val choose : - f:('a -> 'b option) -> - source: ISeq<'a> -> ISeq<'b> + val choose : f:('a->option<'b>) -> source: ISeq<'a> -> ISeq<'b> + [] - val indexed : source: ISeq<'a> -> ISeq + val inline indexed : source: ISeq<'a> -> ISeq + [] val tryPick : f:('T -> 'U option) -> source: ISeq<'T> -> Option<'U> From 7ba76b437311e3c21f4aa0c1b8de4d0517bf86ac Mon Sep 17 00:00:00 2001 From: Jared Hester Date: Wed, 7 Dec 2016 03:55:38 +0100 Subject: [PATCH 53/59] inline choose convert distinct revise distinct hide unnecessarily exposed surface area inline distinctBy inline skipWhile inline takeWhile inline skip inline scan inline take & inline truncate inline windowed inline tail pipeline formatting signature file formatting inline except inline pairwise --- src/fsharp/FSharp.Core/seq.fs | 125 +++--- src/fsharp/FSharp.Core/seq.fsi | 190 ++++----- src/fsharp/FSharp.Core/seqcomposer.fs | 515 ++++++++++++------------- src/fsharp/FSharp.Core/seqcomposer.fsi | 274 ++++--------- 4 files changed, 484 insertions(+), 620 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 138191226d5..6edb97f3110 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -13,6 +13,9 @@ namespace Microsoft.FSharp.Collections open Microsoft.FSharp.Core.CompilerServices open Microsoft.FSharp.Control open Microsoft.FSharp.Collections + open Microsoft.FSharp.Collections.Composer + open Microsoft.FSharp.Collections.Composer.Core + open Microsoft.FSharp.Collections.Composer.Seq open Microsoft.FSharp.Primitives.Basics open Microsoft.FSharp.Collections.IEnumerator @@ -41,22 +44,22 @@ namespace Microsoft.FSharp.Collections #endif let mkDelayedSeq (f: unit -> IEnumerable<'T>) = mkSeq (fun () -> f().GetEnumerator()) let inline indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt))) - + [] - let toComposer (source:seq<'T>): Composer.Core.ISeq<'T> = + let toComposer (source:seq<'T>): Composer.Core.ISeq<'T> = Composer.Seq.toComposer source let inline foreach f (source:seq<_>) = Composer.Seq.foreach f (toComposer source) - let private seqFactory createSeqComponent (source:seq<'T>) = + let private seqFactory (createSeqComponent:#SeqFactory<_,_>) (source:seq<'T>) = match source with | :? Composer.Core.ISeq<'T> as s -> Upcast.enumerable (s.Compose createSeqComponent) | :? array<'T> as a -> Upcast.enumerable (Composer.Seq.Array.create a createSeqComponent) | :? list<'T> as a -> Upcast.enumerable (Composer.Seq.List.create a createSeqComponent) | null -> nullArg "source" | _ -> Upcast.enumerable (Composer.Seq.Enumerable.create source createSeqComponent) - + [] let delay f = mkDelayedSeq f @@ -80,15 +83,15 @@ namespace Microsoft.FSharp.Collections [] let iter f (source : seq<'T>) = - Composer.Seq.iter f (toComposer source) + source |> toComposer |> Composer.Seq.iter f [] let tryHead (source : seq<_>) = - Composer.Seq.tryHead (toComposer source) + source |> toComposer |> Composer.Seq.tryHead [] let skip count (source: seq<_>) = - source |> seqFactory (Composer.Seq.SkipFactory (count, invalidOpFmt)) + source |> toComposer |> Composer.Seq.skip count |> Upcast.enumerable let invalidArgumnetIndex = invalidArgFmt "index" @@ -96,7 +99,7 @@ namespace Microsoft.FSharp.Collections let item i (source : seq<'T>) = if i < 0 then invalidArgInputMustBeNonNegative "index" i else source - |> seqFactory (Composer.Seq.SkipFactory (i, invalidArgumnetIndex)) + |> toComposer |> Composer.Seq.skip i |> Upcast.enumerable |> tryHead |> function | None -> invalidArgFmt "index" "{0}\nseq was short by 1 element" [|SR.GetString SR.notEnoughElements|] @@ -104,26 +107,26 @@ namespace Microsoft.FSharp.Collections [] let tryItem i (source:seq<'T>) = - Composer.Seq.tryItem i (toComposer source) + source |> toComposer |> Composer.Seq.tryItem i [] let nth i (source : seq<'T>) = item i source [] let iteri f (source:seq<'T>) = - Composer.Seq.iteri f (toComposer source) + source |> toComposer |> Composer.Seq.iteri f [] let exists f (source:seq<'T>) = - Composer.Seq.exists f (toComposer source) + source |> toComposer |> Composer.Seq.exists f [] let inline contains element (source:seq<'T>) = - Composer.Seq.contains element (toComposer source) + source |> toComposer |> Composer.Seq.contains element [] let forall f (source:seq<'T>) = - Composer.Seq.forall f (toComposer source) + source |> toComposer |> Composer.Seq.forall f [] let iter2 f (source1 : seq<_>) (source2 : seq<_>) = @@ -171,22 +174,19 @@ namespace Microsoft.FSharp.Collections [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = - Composer.Seq.filter f (toComposer source) - |> Upcast.enumerable + source |> toComposer |> Composer.Seq.filter f |> Upcast.enumerable [] let where f source = filter f source [] let map<'T,'U> (f:'T->'U) (source:seq<'T>) : seq<'U> = - Composer.Seq.map f (toComposer source) - |> Upcast.enumerable + source |> toComposer |> Composer.Seq.map f |> Upcast.enumerable [] let mapi f source = let f' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f - Composer.Seq.mapi_adapt f' (toComposer source) - |> Upcast.enumerable + source |> toComposer |> Composer.Seq.mapi_adapt f' |> Upcast.enumerable [] let mapi2 f source1 source2 = @@ -208,13 +208,11 @@ namespace Microsoft.FSharp.Collections [] let choose f source = - Composer.Seq.choose f (toComposer source) - |> Upcast.enumerable + source |> toComposer |> Composer.Seq.choose f |> Upcast.enumerable [] let indexed source = - Composer.Seq.indexed (toComposer source) - |> Upcast.enumerable + source |> toComposer |> Composer.Seq.indexed |> Upcast.enumerable [] let zip source1 source2 = @@ -231,7 +229,7 @@ namespace Microsoft.FSharp.Collections [] let tryPick f (source : seq<'T>) = - Composer.Seq.tryPick f (toComposer source) + source |> toComposer |> Composer.Seq.tryPick f [] let pick f source = @@ -241,7 +239,7 @@ namespace Microsoft.FSharp.Collections [] let tryFind f (source : seq<'T>) = - Composer.Seq.tryFind f (toComposer source) + source |> toComposer |> Composer.Seq.tryFind f [] let find f source = @@ -254,7 +252,7 @@ namespace Microsoft.FSharp.Collections if count < 0 then invalidArgInputMustBeNonNegative "count" count (* Note: don't create or dispose any IEnumerable if n = 0 *) if count = 0 then empty else - source |> seqFactory (Composer.Seq.TakeFactory count) + source |> toComposer |> Composer.Seq.take count |> Upcast.enumerable [] let isEmpty (source : seq<'T>) = @@ -339,7 +337,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- f.Invoke (this.Value._2, value) Unchecked.defaultof<_> (* return value unsed in ForEach context *) - member this.OnComplete _ = + member this.OnComplete _ = if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -387,7 +385,7 @@ namespace Microsoft.FSharp.Collections this.Value <- c halt () Unchecked.defaultof<_> (* return value unsed in ForEach context *) - member this.OnComplete _ = + member this.OnComplete _ = if this.Value = 0 && e2.MoveNext() then this.Value <- -1 }) |> fun compare -> compare.Value @@ -456,20 +454,18 @@ namespace Microsoft.FSharp.Collections let singleton x = mkSeq (fun () -> IEnumerator.Singleton x) - [] + [] let truncate n (source: seq<'T>) = if n <= 0 then empty else - source |> seqFactory (Composer.Seq.TruncateFactory n) + source |> toComposer |> Composer.Seq.truncate n |> Upcast.enumerable - [] + [] let pairwise<'T> (source:seq<'T>) : seq<'T*'T> = - source |> seqFactory (Composer.Seq.PairwiseFactory ()) + source |> toComposer |> Composer.Seq.pairwise |> Upcast.enumerable - [] - let scan<'T,'State> f (z:'State) (source : seq<'T>): seq<'State> = - let first = [|z|] :> IEnumerable<'State> - let rest = source |> seqFactory (Composer.Seq.ScanFactory (f, z)) - upcast Composer.Seq.Enumerable.ConcatEnumerable [|first; rest;|] + [] + let scan<'T,'State> (folder:'State->'T->'State) (state:'State) (source:seq<'T>) : seq<'State> = + source |> toComposer |> Composer.Seq.scan folder state |> Upcast.enumerable [] let tryFindBack f (source : seq<'T>) = @@ -524,7 +520,7 @@ namespace Microsoft.FSharp.Collections let windowed windowSize (source: seq<_>) = if windowSize <= 0 then invalidArgFmt "windowSize" "{0}\nwindowSize = {1}" [|SR.GetString SR.inputMustBePositive; windowSize|] - source |> seqFactory (Composer.Seq.WindowedFactory (windowSize)) + source |> toComposer |> Composer.Seq.windowed windowSize |> Upcast.enumerable [] let cache (source : seq<'T>) = @@ -642,11 +638,11 @@ namespace Microsoft.FSharp.Collections [] let distinct source = - source |> seqFactory (Composer.Seq.DistinctFactory ()) + source |> toComposer |> Composer.Seq.distinct |> Upcast.enumerable [] let distinctBy keyf source = - source |> seqFactory (Composer.Seq.DistinctByFactory keyf) + source |> toComposer |> Composer.Seq.distinctBy keyf |> Upcast.enumerable [] let sortBy keyf source = @@ -719,7 +715,7 @@ namespace Microsoft.FSharp.Collections #endif then mkDelayedSeq (fun () -> countByValueType keyf source) else mkDelayedSeq (fun () -> countByRefType keyf source) - + [] let inline sum (source:seq<'a>) : 'a = source @@ -750,7 +746,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- this.Value._2 + 1 Unchecked.defaultof<_> (* return value unsed in ForEach context *) - member this.OnComplete _ = + member this.OnComplete _ = if this.Value._2 = 0 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun total -> LanguagePrimitives.DivideByInt< ^a> total.Value._1 total.Value._2 @@ -765,7 +761,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- this.Value._2 + 1 Unchecked.defaultof<_> (* return value unsed in ForEach context *) - member this.OnComplete _ = + member this.OnComplete _ = if this.Value._2 = 0 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) |> fun total -> LanguagePrimitives.DivideByInt< ^U> total.Value._1 total.Value._2 @@ -788,7 +784,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- value Unchecked.defaultof<_> (* return value unsed in ForEach context *) - member this.OnComplete _ = + member this.OnComplete _ = if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -811,7 +807,7 @@ namespace Microsoft.FSharp.Collections | _ -> () Unchecked.defaultof<_> (* return value unsed in ForEach context *) - member this.OnComplete _ = + member this.OnComplete _ = if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -846,7 +842,7 @@ namespace Microsoft.FSharp.Collections this.Value._2 <- value Unchecked.defaultof<_> (* return value unsed in ForEach context *) - member this.OnComplete _ = + member this.OnComplete _ = if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -869,7 +865,7 @@ namespace Microsoft.FSharp.Collections | _ -> () Unchecked.defaultof<_> (* return value unsed in ForEach context *) - member this.OnComplete _ = + member this.OnComplete _ = if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) @@ -892,13 +888,13 @@ namespace Microsoft.FSharp.Collections acc *) - [] - let takeWhile p (source: seq<_>) = - source |> seqFactory (Composer.Seq.TakeWhileFactory p) + [] + let takeWhile predicate (source: seq<_>) = + source |> toComposer |> Composer.Seq.takeWhile predicate |> Upcast.enumerable - [] - let skipWhile p (source: seq<_>) = - source |> seqFactory (Composer.Seq.SkipWhileFactory p) + [] + let skipWhile predicate (source: seq<_>) = + source |> toComposer |> Composer.Seq.skipWhile predicate |> Upcast.enumerable [] let forall2 p (source1: seq<_>) (source2: seq<_>) = @@ -939,7 +935,7 @@ namespace Microsoft.FSharp.Collections halt() Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun exists -> exists.Value - + source1 |> foreach (fun halt -> { new Composer.Core.Folder<_,bool> (false) with @@ -959,10 +955,10 @@ namespace Microsoft.FSharp.Collections | None -> invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString | Some x -> x - [] + [] let tail (source: seq<'T>) = - source |> seqFactory (Composer.Seq.TailFactory ()) - + source |> toComposer |> Composer.Seq.tail |> Upcast.enumerable + [] let tryLast (source : seq<_>) = source @@ -973,7 +969,7 @@ namespace Microsoft.FSharp.Collections this.Value._1 <- false this.Value._2 <- value Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun tried -> + |> fun tried -> if tried.Value._1 then None else @@ -997,9 +993,9 @@ namespace Microsoft.FSharp.Collections else this.Value._3 <- true halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) - member this.OnComplete _ = + member this.OnComplete _ = if this.Value._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString elif this.Value._3 then @@ -1016,8 +1012,8 @@ namespace Microsoft.FSharp.Collections [] let rev source = checkNonNull "source" source - let delayedReverse () = - let array = source |> toArray + let delayedReverse () = + let array = source |> toArray Array.Reverse array array Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedReverse) @@ -1044,10 +1040,11 @@ namespace Microsoft.FSharp.Collections let arr,state = Array.mapFoldBack f array acc readonly arr, state - [] + [] let except (itemsToExclude: seq<'T>) (source: seq<'T>) = checkNonNull "itemsToExclude" itemsToExclude - source |> seqFactory (Composer.Seq.ExceptFactory itemsToExclude) + if isEmpty itemsToExclude then source else + source |> toComposer |> Composer.Seq.except itemsToExclude |> Upcast.enumerable [] let chunkBySize chunkSize (source : seq<_>) = diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi index f06c676e4de..76ca68bb866 100644 --- a/src/fsharp/FSharp.Core/seq.fsi +++ b/src/fsharp/FSharp.Core/seq.fsi @@ -7,12 +7,12 @@ namespace Microsoft.FSharp.Collections open System.Collections.Generic open Microsoft.FSharp.Core open Microsoft.FSharp.Collections - + /// Basic operations on IEnumerables. [] [] - module Seq = + module Seq = /// Returns a new sequence that contains the cartesian product of the two input sequences. /// The first sequence. /// The second sequence. @@ -24,7 +24,7 @@ namespace Microsoft.FSharp.Collections /// Wraps the two given enumerations as a single concatenated /// enumeration. /// - /// The returned sequence may be passed between threads safely. However, + /// The returned sequence may be passed between threads safely. However, /// individual IEnumerator values generated from the returned sequence should not be accessed /// concurrently. /// @@ -36,11 +36,11 @@ namespace Microsoft.FSharp.Collections /// Thrown when either of the two provided sequences is /// null. [] - val append: source1:seq<'T> -> source2:seq<'T> -> seq<'T> + val append: source1:seq<'T> -> source2:seq<'T> -> seq<'T> /// Returns the average of the elements in the sequence. /// - /// The elements are averaged using the + operator, DivideByInt method and Zero property + /// The elements are averaged using the + operator, DivideByInt method and Zero property /// associated with the element type. /// /// The input sequence. @@ -50,15 +50,15 @@ namespace Microsoft.FSharp.Collections /// Thrown when the input sequence is null. /// Thrown when the input sequence has zero elements. [] - val inline average : source:seq<(^T)> -> ^T - when ^T : (static member ( + ) : ^T * ^T -> ^T) - and ^T : (static member DivideByInt : ^T * int -> ^T) + val inline average : source:seq<(^T)> -> ^T + when ^T : (static member ( + ) : ^T * ^T -> ^T) + and ^T : (static member DivideByInt : ^T * int -> ^T) and ^T : (static member Zero : ^T) - /// Returns the average of the results generated by applying the function to each element + /// Returns the average of the results generated by applying the function to each element /// of the sequence. /// - /// The elements are averaged using the + operator, DivideByInt method and Zero property + /// The elements are averaged using the + operator, DivideByInt method and Zero property /// associated with the generated type. /// /// A function applied to transform each element of the sequence. @@ -69,29 +69,29 @@ namespace Microsoft.FSharp.Collections /// Thrown when the input sequence is null. /// Thrown when the input sequence has zero elements. [] - val inline averageBy : projection:('T -> ^U) -> source:seq<'T> -> ^U - when ^U : (static member ( + ) : ^U * ^U -> ^U) - and ^U : (static member DivideByInt : ^U * int -> ^U) + val inline averageBy : projection:('T -> ^U) -> source:seq<'T> -> ^U + when ^U : (static member ( + ) : ^U * ^U -> ^U) + and ^U : (static member DivideByInt : ^U * int -> ^U) and ^U : (static member Zero : ^U) /// Returns a sequence that corresponds to a cached version of the input sequence. - /// This result sequence will have the same elements as the input sequence. The result - /// can be enumerated multiple times. The input sequence will be enumerated at most + /// This result sequence will have the same elements as the input sequence. The result + /// can be enumerated multiple times. The input sequence will be enumerated at most /// once and only as far as is necessary. Caching a sequence is typically useful when repeatedly /// evaluating items in the original sequence is computationally expensive or if /// iterating the sequence causes side-effects that the user does not want to be /// repeated multiple times. /// /// Enumeration of the result sequence is thread safe in the sense that multiple independent IEnumerator - /// values may be used simultaneously from different threads (accesses to + /// values may be used simultaneously from different threads (accesses to /// the internal lookaside table are thread safe). Each individual IEnumerator /// is not typically thread safe and should not be accessed concurrently. /// /// Once enumeration of the input sequence has started, /// it's enumerator will be kept live by this object until the enumeration has completed. - /// At that point, the enumerator will be disposed. + /// At that point, the enumerator will be disposed. /// - /// The enumerator may be disposed and underlying cache storage released by + /// The enumerator may be disposed and underlying cache storage released by /// converting the returned sequence object to type IDisposable, and calling the Dispose method /// on this object. The sequence object may then be re-enumerated and a fresh enumerator will /// be used. @@ -110,7 +110,7 @@ namespace Microsoft.FSharp.Collections /// An incorrect type annotation may result in runtime type /// errors. /// Individual IEnumerator values generated from the returned sequence should not be accessed concurrently. - /// + /// /// The input sequence. /// /// The result sequence. @@ -123,7 +123,7 @@ namespace Microsoft.FSharp.Collections /// the list comprised of the results "x" for each element where /// the function returns Some(x). /// - /// The returned sequence may be passed between threads safely. However, + /// The returned sequence may be passed between threads safely. However, /// individual IEnumerator values generated from the returned sequence should not /// be accessed concurrently. /// @@ -131,7 +131,7 @@ namespace Microsoft.FSharp.Collections /// The input sequence of type T. /// /// The result sequence. - /// + /// /// Thrown when the input sequence is null. [] val choose: chooser:('T -> 'U option) -> source:seq<'T> -> seq<'U> @@ -179,7 +179,7 @@ namespace Microsoft.FSharp.Collections /// Combines the given enumeration-of-enumerations as a single concatenated /// enumeration. /// - /// The returned sequence may be passed between threads safely. However, + /// The returned sequence may be passed between threads safely. However, /// individual IEnumerator values generated from the returned sequence should not be accessed concurrently. /// /// The input enumeration-of-enumerations. @@ -200,10 +200,10 @@ namespace Microsoft.FSharp.Collections /// Applies a key-generating function to each element of a sequence and returns a sequence yielding unique /// keys and their number of occurrences in the original sequence. - /// - /// Note that this function returns a sequence that digests the whole initial sequence as soon as - /// that sequence is iterated. As a result this function should not be used with - /// large or infinite sequences. The function makes no assumption on the ordering of the original + /// + /// Note that this function returns a sequence that digests the whole initial sequence as soon as + /// that sequence is iterated. As a result this function should not be used with + /// large or infinite sequences. The function makes no assumption on the ordering of the original /// sequence. /// /// A function transforming each item of the input sequence into a key to be @@ -219,7 +219,7 @@ namespace Microsoft.FSharp.Collections /// Returns a sequence that is built from the given delayed specification of a /// sequence. /// - /// The input function is evaluated each time an IEnumerator for the sequence + /// The input function is evaluated each time an IEnumerator for the sequence /// is requested. /// /// The generating function for the sequence. @@ -238,7 +238,7 @@ namespace Microsoft.FSharp.Collections [] val distinct: source:seq<'T> -> seq<'T> when 'T : equality - /// Returns a sequence that contains no duplicate entries according to the + /// Returns a sequence that contains no duplicate entries according to the /// generic hash and equality comparisons on the keys returned by the given key-generating function. /// If an element occurs multiple times in the sequence then the later occurrences are discarded. /// @@ -290,8 +290,8 @@ namespace Microsoft.FSharp.Collections /// Tests if any element of the sequence satisfies the given predicate. /// - /// The predicate is applied to the elements of the input sequence. If any application - /// returns true then the overall result is true and no further elements are tested. + /// The predicate is applied to the elements of the input sequence. If any application + /// returns true then the overall result is true and no further elements are tested. /// Otherwise, false is returned. /// /// A function to test each item of the input sequence. @@ -305,9 +305,9 @@ namespace Microsoft.FSharp.Collections /// Tests if any pair of corresponding elements of the input sequences satisfies the given predicate. /// - /// The predicate is applied to matching elements in the two sequences up to the lesser of the - /// two lengths of the collections. If any application returns true then the overall result is - /// true and no further elements are tested. Otherwise, false is returned. If one sequence is shorter than + /// The predicate is applied to matching elements in the two sequences up to the lesser of the + /// two lengths of the collections. If any application returns true then the overall result is + /// true and no further elements are tested. Otherwise, false is returned. If one sequence is shorter than /// the other then the remaining elements of the longer sequence are ignored. /// /// A function to test each pair of items from the input sequences. @@ -323,7 +323,7 @@ namespace Microsoft.FSharp.Collections /// Returns a new collection containing only the elements of the collection /// for which the given predicate returns "true". This is a synonym for Seq.where. /// - /// The returned sequence may be passed between threads safely. However, + /// The returned sequence may be passed between threads safely. However, /// individual IEnumerator values generated from the returned sequence should not be accessed concurrently. /// /// Remember sequence is lazy, effects are delayed until it is enumerated. @@ -333,18 +333,18 @@ namespace Microsoft.FSharp.Collections /// /// The result sequence. /// - /// Thrown when the input sequence is null. + /// Thrown when the input sequence is null. [] val filter: predicate:('T -> bool) -> source:seq<'T> -> seq<'T> /// Returns a new collection containing only the elements of the collection /// for which the given predicate returns "true". /// - /// The returned sequence may be passed between threads safely. However, + /// The returned sequence may be passed between threads safely. However, /// individual IEnumerator values generated from the returned sequence should not be accessed concurrently. /// /// Remember sequence is lazy, effects are delayed until it is enumerated. - /// + /// /// A synonym for Seq.filter. /// /// A function to test whether each item in the input sequence should be included in the output. @@ -352,7 +352,7 @@ namespace Microsoft.FSharp.Collections /// /// The result sequence. /// - /// Thrown when the input sequence is null. + /// Thrown when the input sequence is null. [] val where: predicate:('T -> bool) -> source:seq<'T> -> seq<'T> @@ -409,7 +409,7 @@ namespace Microsoft.FSharp.Collections val findIndexBack: predicate:('T -> bool) -> source:seq<'T> -> int /// Applies a function to each element of the collection, threading an accumulator argument - /// through the computation. If the input function is f and the elements are i0...iN + /// through the computation. If the input function is f and the elements are i0...iN /// then computes f (... (f s i0)...) iN /// /// A function that updates the state with each element from the sequence. @@ -463,8 +463,8 @@ namespace Microsoft.FSharp.Collections /// Tests if all elements of the sequence satisfy the given predicate. /// - /// The predicate is applied to the elements of the input sequence. If any application - /// returns false then the overall result is false and no further elements are tested. + /// The predicate is applied to the elements of the input sequence. If any application + /// returns false then the overall result is false and no further elements are tested. /// Otherwise, true is returned. /// /// A function to test an element of the input sequence. @@ -477,7 +477,7 @@ namespace Microsoft.FSharp.Collections val forall: predicate:('T -> bool) -> source:seq<'T> -> bool /// Tests the all pairs of elements drawn from the two sequences satisfy the - /// given predicate. If one sequence is shorter than + /// given predicate. If one sequence is shorter than /// the other then the remaining elements of the longer sequence are ignored. /// /// A function to test pairs of elements from the input sequences. @@ -490,13 +490,13 @@ namespace Microsoft.FSharp.Collections [] val forall2: predicate:('T1 -> 'T2 -> bool) -> source1:seq<'T1> -> source2:seq<'T2> -> bool - /// Applies a key-generating function to each element of a sequence and yields a sequence of - /// unique keys. Each unique key contains a sequence of all elements that match + /// Applies a key-generating function to each element of a sequence and yields a sequence of + /// unique keys. Each unique key contains a sequence of all elements that match /// to this key. - /// - /// This function returns a sequence that digests the whole initial sequence as soon as - /// that sequence is iterated. As a result this function should not be used with - /// large or infinite sequences. The function makes no assumption on the ordering of the original + /// + /// This function returns a sequence that digests the whole initial sequence as soon as + /// that sequence is iterated. As a result this function should not be used with + /// large or infinite sequences. The function makes no assumption on the ordering of the original /// sequence. /// /// A function that transforms an element of the sequence into a comparable key. @@ -580,7 +580,7 @@ namespace Microsoft.FSharp.Collections /// initialization. The function is passed the index of the item being /// generated. /// - /// The returned sequence may be passed between threads safely. However, + /// The returned sequence may be passed between threads safely. However, /// individual IEnumerator values generated from the returned sequence should not be accessed concurrently. /// /// The maximum number of items to generate for the sequence. @@ -591,14 +591,14 @@ namespace Microsoft.FSharp.Collections /// Thrown when count is negative. [] val init: count:int -> initializer:(int -> 'T) -> seq<'T> - + /// Generates a new sequence which, when iterated, will return successive /// elements by calling the given function. The results of calling the function /// will not be saved, that is the function will be reapplied as necessary to /// regenerate the elements. The function is passed the index of the item being /// generated. /// - /// The returned sequence may be passed between threads safely. However, + /// The returned sequence may be passed between threads safely. However, /// individual IEnumerator values generated from the returned sequence should not be accessed concurrently. /// Iteration can continue up to Int32.MaxValue. /// @@ -636,7 +636,7 @@ namespace Microsoft.FSharp.Collections [] val iteri: action:(int -> 'T -> unit) -> source:seq<'T> -> unit - /// Applies the given function to two collections simultaneously. If one sequence is shorter than + /// Applies the given function to two collections simultaneously. If one sequence is shorter than /// the other then the remaining elements of the longer sequence are ignored. /// /// A function to apply to each pair of elements from the input sequences. @@ -647,7 +647,7 @@ namespace Microsoft.FSharp.Collections [] val iter2: action:('T1 -> 'T2 -> unit) -> source1:seq<'T1> -> source2:seq<'T2> -> unit - /// Applies the given function to two collections simultaneously. If one sequence is shorter than + /// Applies the given function to two collections simultaneously. If one sequence is shorter than /// the other then the remaining elements of the longer sequence are ignored. The integer passed to the /// function indicates the index of element. /// @@ -674,7 +674,7 @@ namespace Microsoft.FSharp.Collections /// as elements are demanded using the MoveNext method on enumerators retrieved from the /// object. /// - /// The returned sequence may be passed between threads safely. However, + /// The returned sequence may be passed between threads safely. However, /// individual IEnumerator values generated from the returned sequence should not be accessed concurrently. /// /// A function to transform items from the input sequence. @@ -687,7 +687,7 @@ namespace Microsoft.FSharp.Collections val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U> /// Builds a new collection whose elements are the results of applying the given function - /// to the corresponding pairs of elements from the two sequences. If one input sequence is shorter than + /// to the corresponding pairs of elements from the two sequences. If one input sequence is shorter than /// the other then the remaining elements of the longer sequence are ignored. /// /// A function to transform pairs of items from the input sequences. @@ -755,7 +755,7 @@ namespace Microsoft.FSharp.Collections val mapi: mapping:(int -> 'T -> 'U) -> source:seq<'T> -> seq<'U> /// Builds a new collection whose elements are the results of applying the given function - /// to the corresponding pairs of elements from the two sequences. If one input sequence is shorter than + /// to the corresponding pairs of elements from the two sequences. If one input sequence is shorter than /// the other then the remaining elements of the longer sequence are ignored. The integer index passed to the /// function indicates the index (from 0) of element being transformed. /// @@ -778,7 +778,7 @@ namespace Microsoft.FSharp.Collections /// /// The largest element of the sequence. [] - val inline max : source:seq<'T> -> 'T when 'T : comparison + val inline max : source:seq<'T> -> 'T when 'T : comparison /// Returns the greatest of all elements of the sequence, compared via Operators.max on the function result. /// @@ -790,7 +790,7 @@ namespace Microsoft.FSharp.Collections /// Thrown when the input sequence is null. /// Thrown when the input sequence is empty. [] - val inline maxBy : projection:('T -> 'U) -> source:seq<'T> -> 'T when 'U : comparison + val inline maxBy : projection:('T -> 'U) -> source:seq<'T> -> 'T when 'U : comparison (* /// Returns the greatest function result from the elements of the sequence, compared via Operators.max. @@ -803,7 +803,7 @@ namespace Microsoft.FSharp.Collections /// Thrown when the input sequence is null. /// Thrown when the input sequence is empty. [] - val inline maxValBy : projection:('T -> 'U) -> source:seq<'T> -> 'U when 'U : comparison + val inline maxValBy : projection:('T -> 'U) -> source:seq<'T> -> 'U when 'U : comparison *) /// Returns the lowest of all elements of the sequence, compared via Operators.min. @@ -815,7 +815,7 @@ namespace Microsoft.FSharp.Collections /// Thrown when the input sequence is null. /// Thrown when the input sequence is empty. [] - val inline min : source:seq<'T> -> 'T when 'T : comparison + val inline min : source:seq<'T> -> 'T when 'T : comparison /// Returns the lowest of all elements of the sequence, compared via Operators.min on the function result. /// @@ -827,7 +827,7 @@ namespace Microsoft.FSharp.Collections /// Thrown when the input sequence is null. /// Thrown when the input sequence is empty. [] - val inline minBy : projection:('T -> 'U) -> source:seq<'T> -> 'T when 'U : comparison + val inline minBy : projection:('T -> 'U) -> source:seq<'T> -> 'T when 'U : comparison (* /// Returns the lowest function result from the elements of the sequence, compared via Operators.max. @@ -840,7 +840,7 @@ namespace Microsoft.FSharp.Collections /// Thrown when the input sequence is null. /// Thrown when the input sequence is empty. [] - val inline minValBy : projection:('T -> 'U) -> source:seq<'T> -> 'U when 'U : comparison + val inline minValBy : projection:('T -> 'U) -> source:seq<'T> -> 'U when 'U : comparison *) /// Computes the nth element in the collection. @@ -916,10 +916,10 @@ namespace Microsoft.FSharp.Collections /// Thrown when every item of the sequence /// evaluates to None when the given function is applied. [] - val pick: chooser:('T -> 'U option) -> source:seq<'T> -> 'U + val pick: chooser:('T -> 'U option) -> source:seq<'T> -> 'U - /// Builds a new sequence object that delegates to the given sequence object. This ensures - /// the original sequence cannot be rediscovered and mutated by a type cast. For example, + /// Builds a new sequence object that delegates to the given sequence object. This ensures + /// the original sequence cannot be rediscovered and mutated by a type cast. For example, /// if given an array the returned sequence will return the elements of the array, but /// you cannot cast the returned sequence object to an array. /// @@ -933,7 +933,7 @@ namespace Microsoft.FSharp.Collections /// Applies a function to each element of the sequence, threading an accumulator argument /// through the computation. Begin by applying the function to the first two elements. - /// Then feed this result into the function along with the third element and so on. + /// Then feed this result into the function along with the third element and so on. /// Return the final result. /// /// A function that takes in the current accumulated result and the next @@ -955,7 +955,7 @@ namespace Microsoft.FSharp.Collections val replicate: count:int -> initial:'T -> seq<'T> /// Applies a function to each element of the sequence, starting from the end, threading an accumulator argument - /// through the computation. If the input function is f and the elements are i0...iN + /// through the computation. If the input function is f and the elements are i0...iN /// then computes f i0 (...(f iN-1 iN)). /// A function that takes in the next-to-last element of the sequence and the /// current accumulated result to produce the next accumulated result. @@ -1022,7 +1022,7 @@ namespace Microsoft.FSharp.Collections [] val skip: count:int -> source:seq<'T> -> seq<'T> - /// Returns a sequence that, when iterated, skips elements of the underlying sequence while the + /// Returns a sequence that, when iterated, skips elements of the underlying sequence while the /// given predicate returns True, and then yields the remaining elements of the sequence. /// /// A function that evaluates an element of the sequence to a boolean value. @@ -1035,10 +1035,10 @@ namespace Microsoft.FSharp.Collections val skipWhile: predicate:('T -> bool) -> source:seq<'T> -> seq<'T> /// Yields a sequence ordered by keys. - /// - /// This function returns a sequence that digests the whole initial sequence as soon as - /// that sequence is iterated. As a result this function should not be used with - /// large or infinite sequences. The function makes no assumption on the ordering of the original + /// + /// This function returns a sequence that digests the whole initial sequence as soon as + /// that sequence is iterated. As a result this function should not be used with + /// large or infinite sequences. The function makes no assumption on the ordering of the original /// sequence. /// /// This is a stable sort, that is the original order of equal elements is preserved. @@ -1067,11 +1067,11 @@ namespace Microsoft.FSharp.Collections val sortWith : comparer:('T -> 'T -> int) -> source:seq<'T> -> seq<'T> /// Applies a key-generating function to each element of a sequence and yield a sequence ordered - /// by keys. The keys are compared using generic comparison as implemented by Operators.compare. - /// - /// This function returns a sequence that digests the whole initial sequence as soon as - /// that sequence is iterated. As a result this function should not be used with - /// large or infinite sequences. The function makes no assumption on the ordering of the original + /// by keys. The keys are compared using generic comparison as implemented by Operators.compare. + /// + /// This function returns a sequence that digests the whole initial sequence as soon as + /// that sequence is iterated. As a result this function should not be used with + /// large or infinite sequences. The function makes no assumption on the ordering of the original /// sequence. /// /// This is a stable sort, that is the original order of equal elements is preserved. @@ -1083,13 +1083,13 @@ namespace Microsoft.FSharp.Collections /// /// Thrown when the input sequence is null. [] - val sortBy : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> when 'Key : comparison + val sortBy : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> when 'Key : comparison /// Yields a sequence ordered descending by keys. - /// - /// This function returns a sequence that digests the whole initial sequence as soon as - /// that sequence is iterated. As a result this function should not be used with - /// large or infinite sequences. The function makes no assumption on the ordering of the original + /// + /// This function returns a sequence that digests the whole initial sequence as soon as + /// that sequence is iterated. As a result this function should not be used with + /// large or infinite sequences. The function makes no assumption on the ordering of the original /// sequence. /// /// This is a stable sort, that is the original order of equal elements is preserved. @@ -1103,11 +1103,11 @@ namespace Microsoft.FSharp.Collections val inline sortDescending : source:seq<'T> -> seq<'T> when 'T : comparison /// Applies a key-generating function to each element of a sequence and yield a sequence ordered - /// descending by keys. The keys are compared using generic comparison as implemented by Operators.compare. - /// - /// This function returns a sequence that digests the whole initial sequence as soon as - /// that sequence is iterated. As a result this function should not be used with - /// large or infinite sequences. The function makes no assumption on the ordering of the original + /// descending by keys. The keys are compared using generic comparison as implemented by Operators.compare. + /// + /// This function returns a sequence that digests the whole initial sequence as soon as + /// that sequence is iterated. As a result this function should not be used with + /// large or infinite sequences. The function makes no assumption on the ordering of the original /// sequence. /// /// This is a stable sort, that is the original order of equal elements is preserved. @@ -1129,8 +1129,8 @@ namespace Microsoft.FSharp.Collections /// /// The computed sum. [] - val inline sum : source:seq<(^T)> -> ^T - when ^T : (static member ( + ) : ^T * ^T -> ^T) + val inline sum : source:seq<(^T)> -> ^T + when ^T : (static member ( + ) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) /// Returns the sum of the results generated by applying the function to each element of the sequence. @@ -1141,8 +1141,8 @@ namespace Microsoft.FSharp.Collections /// /// The computed sum. [] - val inline sumBy : projection:('T -> ^U) -> source:seq<'T> -> ^U - when ^U : (static member ( + ) : ^U * ^U -> ^U) + val inline sumBy : projection:('T -> ^U) -> source:seq<'T> -> ^U + when ^U : (static member ( + ) : ^U * ^U -> ^U) and ^U : (static member Zero : ^U) /// Returns a sequence that skips 1 element of the underlying sequence and then yields the @@ -1174,7 +1174,7 @@ namespace Microsoft.FSharp.Collections [] val take: count:int -> source:seq<'T> -> seq<'T> - /// Returns a sequence that, when iterated, yields elements of the underlying sequence while the + /// Returns a sequence that, when iterated, yields elements of the underlying sequence while the /// given predicate returns True, and then returns no further elements. /// /// A function that evaluates to false when no more items should be returned. @@ -1195,7 +1195,7 @@ namespace Microsoft.FSharp.Collections /// Thrown when the input sequence is null. [] val toArray: source:seq<'T> -> 'T[] - + /// Builds an SeqEnumerable from the given collection. /// /// The input sequence. @@ -1240,7 +1240,7 @@ namespace Microsoft.FSharp.Collections [] val tryFindBack: predicate:('T -> bool) -> source:seq<'T> -> 'T option - /// Returns the index of the first element in the sequence + /// Returns the index of the first element in the sequence /// that satisfies the given predicate. Return None if no such element exists. /// /// A function that evaluates to a Boolean when given an item in the sequence. @@ -1304,7 +1304,7 @@ namespace Microsoft.FSharp.Collections /// /// The stream will be recomputed each time an IEnumerator is requested and iterated for the Seq. /// - /// The returned sequence may be passed between threads safely. However, + /// The returned sequence may be passed between threads safely. However, /// individual IEnumerator values generated from the returned sequence should not be accessed concurrently. /// /// A function that takes in the current state and returns an option tuple of the next diff --git a/src/fsharp/FSharp.Core/seqcomposer.fs b/src/fsharp/FSharp.Core/seqcomposer.fs index 6ebe4e26cf8..3026661ab3b 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fs +++ b/src/fsharp/FSharp.Core/seqcomposer.fs @@ -43,7 +43,7 @@ namespace Microsoft.FSharp.Collections member this.OnComplete (_, terminatingIdx) = this.OnComplete terminatingIdx - member this.OnDispose _ = + member this.OnDispose _ = try this.OnDispose () finally () @@ -94,7 +94,7 @@ namespace Microsoft.FSharp.Collections abstract member Compose<'U> : (SeqFactory<'T,'U>) -> ISeq<'U> abstract member ForEach<'consumer when 'consumer :> Consumer<'T,'T>> : f:((unit->unit)->'consumer) -> 'consumer - open Core + open Core module internal TailCall = // used for performance reasons; these are not recursive calls, so should be safe @@ -124,22 +124,6 @@ namespace Microsoft.FSharp.Collections static member Combine (first:SeqFactory<'T,'U>) (second:SeqFactory<'U,'V>) : SeqFactory<'T,'V> = upcast ComposedFactory(first, second, first.PipeIdx+1) - and ChooseFactory<'T,'U> (filter:'T->option<'U>) = - inherit SeqFactory<'T,'U> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'T,'V> = upcast Choose (filter, next) - - and DistinctFactory<'T when 'T: equality> () = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Distinct (next) - - and DistinctByFactory<'T,'Key when 'Key: equality> (keyFunction:'T-> 'Key) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast DistinctBy (keyFunction, next) - - and ExceptFactory<'T when 'T: equality> (itemsToExclude: seq<'T>) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Except (itemsToExclude, next) - and IdentityFactory<'T> () = inherit SeqFactory<'T,'T> () static let singleton : SeqFactory<'T,'T> = upcast (IdentityFactory<'T>()) @@ -162,42 +146,6 @@ namespace Microsoft.FSharp.Collections inherit SeqFactory<'First,'U> () override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, outOfBand, next, pipeIdx) - and PairwiseFactory<'T> () = - inherit SeqFactory<'T,'T*'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T*'T,'V>) : Consumer<'T,'V> = upcast Pairwise (next) - - and ScanFactory<'T,'State> (folder:'State->'T->'State, initialState:'State) = - inherit SeqFactory<'T,'State> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'State,'V>) : Consumer<'T,'V> = upcast Scan<_,_,_> (folder, initialState, next) - - and SkipFactory<'T> (count:int, onNotEnoughElements) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Skip (count, onNotEnoughElements, next) - - and SkipWhileFactory<'T> (predicate:'T->bool) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast SkipWhile (predicate, next) - - and TakeWhileFactory<'T> (predicate:'T->bool) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast TakeWhile (predicate, outOfBand, next, pipeIdx) - - and TakeFactory<'T> (count:int) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Take (count, outOfBand, next, pipeIdx) - - and TailFactory<'T> () = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Tail<'T,'V> (next) - - and TruncateFactory<'T> (count:int) = - inherit SeqFactory<'T,'T> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = upcast Truncate (count, outOfBand, next, pipeIdx) - - and WindowedFactory<'T> (windowSize:int) = - inherit SeqFactory<'T, 'T[]> () - override this.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T[],'V>) : Consumer<'T,'V> = upcast Windowed (windowSize, next) - and ISkipping = // Seq.init(Infinite)? lazily uses Current. The only Composer component that can do that is Skip // and it can only do it at the start of a sequence @@ -233,47 +181,6 @@ namespace Microsoft.FSharp.Collections try this.OnDispose () finally next.OnDispose (&stopTailCall) - and Choose<'T,'U,'V> (choose:'T->option<'U>, next:Consumer<'U,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) - - override __.ProcessNext (input:'T) : bool = - match choose input with - | Some value -> TailCall.avoid (next.ProcessNext value) - | None -> false - - and Distinct<'T,'V when 'T: equality> (next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) - - let hashSet = HashSet<'T>(HashIdentity.Structural<'T>) - - override __.ProcessNext (input:'T) : bool = - if hashSet.Add input then - TailCall.avoid (next.ProcessNext input) - else - false - - and DistinctBy<'T,'Key,'V when 'Key: equality> (keyFunction: 'T -> 'Key, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) - - let hashSet = HashSet<'Key>(HashIdentity.Structural<'Key>) - - override __.ProcessNext (input:'T) : bool = - if hashSet.Add(keyFunction input) then - TailCall.avoid (next.ProcessNext input) - else - false - - and Except<'T,'V when 'T: equality> (itemsToExclude: seq<'T>, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) - - let cached = lazy(HashSet(itemsToExclude, HashIdentity.Structural)) - - override __.ProcessNext (input:'T) : bool = - if cached.Value.Add input then - TailCall.avoid (next.ProcessNext input) - else - false - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = inherit SeqComponent<'First,'V>(Upcast.iCompletionChaining next) @@ -342,153 +249,6 @@ namespace Microsoft.FSharp.Collections override __.OnDispose () = input2.Dispose () - and Pairwise<'T,'V> (next:Consumer<'T*'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) - - let mutable isFirst = true - let mutable lastValue = Unchecked.defaultof<'T> - - override __.ProcessNext (input:'T) : bool = - if isFirst then - lastValue <- input - isFirst <- false - false - else - let currentPair = lastValue, input - lastValue <- input - TailCall.avoid (next.ProcessNext currentPair) - - and Scan<'T,'State,'V> (folder:'State->'T->'State, initialState: 'State, next:Consumer<'State,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) - - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder - let mutable foldResult = initialState - - override __.ProcessNext (input:'T) : bool = - foldResult <- f.Invoke(foldResult, input) - TailCall.avoid (next.ProcessNext foldResult) - - and Skip<'T,'V> (skipCount:int, notEnoughElements:string->array->unit, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) - - let mutable count = 0 - - interface ISkipping with - member __.Skipping () = - if count < skipCount then - count <- count + 1 - true - else - false - - override __.ProcessNext (input:'T) : bool = - if count < skipCount then - count <- count + 1 - false - else - TailCall.avoid (next.ProcessNext input) - - override __.OnComplete _ = - if count < skipCount then - let x = skipCount - count - notEnoughElements "{0}\ntried to skip {1} {2} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - - and SkipWhile<'T,'V> (predicate:'T->bool, next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) - - let mutable skip = true - - override __.ProcessNext (input:'T) : bool = - if skip then - skip <- predicate input - if skip then - false - else - TailCall.avoid (next.ProcessNext input) - else - TailCall.avoid (next.ProcessNext input) - - and Take<'T,'V> (takeCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipelineIdx:int) = - inherit Truncate<'T, 'V>(takeCount, outOfBand, next, pipelineIdx) - - override this.OnComplete terminatingIdx = - if terminatingIdx < pipelineIdx && this.Count < takeCount then - let x = takeCount - this.Count - invalidOpFmt "tried to take {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - - and TakeWhile<'T,'V> (predicate:'T->bool, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) - - override __.ProcessNext (input:'T) : bool = - if predicate input then - TailCall.avoid (next.ProcessNext input) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - and Tail<'T, 'V> (next:Consumer<'T,'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) - - let mutable first = true - - override __.ProcessNext (input:'T) : bool = - if first then - first <- false - false - else - TailCall.avoid (next.ProcessNext input) - - override this.OnComplete _ = - if first then - invalidArg "source" (SR.GetString(SR.notEnoughElements)) - - and Truncate<'T,'V> (truncateCount:int, outOfBand:IOutOfBand, next:Consumer<'T,'V>, pipeIdx:int) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) - - let mutable count = 0 - - member __.Count = count - - override __.ProcessNext (input:'T) : bool = - if count < truncateCount then - count <- count + 1 - if count = truncateCount then - outOfBand.StopFurtherProcessing pipeIdx - TailCall.avoid (next.ProcessNext input) - else - outOfBand.StopFurtherProcessing pipeIdx - false - - and Windowed<'T,'V> (windowSize: int, next:Consumer<'T[],'V>) = - inherit SeqComponent<'T,'V>(Upcast.iCompletionChaining next) - - let circularBuffer = Array.zeroCreateUnchecked windowSize - let mutable idx = 0 - - let mutable priming = windowSize - 1 - - override __.ProcessNext (input:'T) : bool = - circularBuffer.[idx] <- input - - idx <- idx + 1 - if idx = windowSize then - idx <- 0 - - if priming > 0 then - priming <- priming - 1 - false - else - if windowSize < 32 then - let window = Array.init windowSize (fun i -> circularBuffer.[(idx+i) % windowSize]) - TailCall.avoid (next.ProcessNext window) - else - let window = Array.zeroCreateUnchecked windowSize - Array.Copy(circularBuffer, idx, window, 0, windowSize - idx) - Array.Copy(circularBuffer, 0, window, windowSize - idx, idx) - TailCall.avoid (next.ProcessNext window) - type SeqProcessNextStates = | InProcess = 0 | NotStarted = 1 @@ -496,7 +256,7 @@ namespace Microsoft.FSharp.Collections type Result<'T>() = let mutable haltedIdx = 0 - + member val Current = Unchecked.defaultof<'T> with get, set member val SeqState = SeqProcessNextStates.NotStarted with get, set member __.HaltedIdx = haltedIdx @@ -538,14 +298,14 @@ namespace Microsoft.FSharp.Collections | _ -> () iterate alist - let unfold (generator:'S->option<'T*'S>) state (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = + let unfold (generator:'S->option<'T*'S>) state (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = let rec iterate current = match outOfBand.HaltedIdx, generator current with | 0, Some (item, next) -> consumer.ProcessNext item |> ignore iterate next | _ -> () - + iterate state let makeIsSkipping (consumer:Consumer<'T,'U>) = @@ -591,7 +351,7 @@ namespace Microsoft.FSharp.Collections interface IDisposable with member __.Dispose () = () - type EmptyEnumerators<'T>() = + type EmptyEnumerators<'T>() = static let element : IEnumerator<'T> = upcast (new Empty<'T> ()) static member Element = element @@ -842,7 +602,7 @@ namespace Microsoft.FSharp.Collections let rec moveNext current = match result.HaltedIdx, current with - | 0, head::tail -> + | 0, head::tail -> if seqComponent.ProcessNext head then list <- tail true @@ -953,7 +713,7 @@ namespace Microsoft.FSharp.Collections // Skip can only is only checked at the start of the sequence, so once // triggered, we stay triggered. maybeSkipping <- isSkipping () - + if maybeSkipping then moveNext () elif seqComponent.ProcessNext (f idx) then @@ -1057,7 +817,7 @@ namespace Microsoft.FSharp.Collections ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (Upcast.enumerable this)) [] - let toComposer (source:seq<'T>) : ISeq<'T> = + let toComposer (source:seq<'T>) : ISeq<'T> = match source with | :? ISeq<'T> as s -> s | :? array<'T> as a -> Upcast.seq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) @@ -1109,11 +869,7 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun head -> head.Value - [] - let tryItem i (source:ISeq<'T>) = - if i < 0 then None else - source.Compose (SkipFactory(i, fun _ _ -> ())) - |> tryHead + [] let iteri f (source:ISeq<'T>) = @@ -1128,6 +884,17 @@ namespace Microsoft.FSharp.Collections Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> ignore + [] + let inline except (itemsToExclude: seq<'T>) (source:ISeq<'T>) : ISeq<'T> when 'T:equality = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { new SeqComponentSimpleValue<'T,'V,Lazy>> + (Upcast.iCompletionChaining next,lazy(HashSet<'T>(itemsToExclude,HashIdentity.Structural<'T>))) with + override this.ProcessNext (input:'T) : bool = + if this.Value.Value.Add input then TailCall.avoid (next.ProcessNext input) + else false + }} + [] let exists f (source:ISeq<'T>) = source @@ -1163,13 +930,13 @@ namespace Microsoft.FSharp.Collections halt () Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) |> fun forall -> forall.Value - + [] let inline filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = source |> compose { new SeqFactory<'T,'T>() with member __.Create _ _ next = upcast { new SeqComponentSimple<'T,'V>(Upcast.iCompletionChaining next) with - member __.ProcessNext input = + member __.ProcessNext input = if f input then TailCall.avoid (next.ProcessNext input) else false } } @@ -1178,7 +945,7 @@ namespace Microsoft.FSharp.Collections source |> compose { new SeqFactory<'T,'U>() with member __.Create _ _ next = upcast { new SeqComponentSimple<'T,'V>(Upcast.iCompletionChaining next) with - member __.ProcessNext input = + member __.ProcessNext input = TailCall.avoid (next.ProcessNext (f input)) } } [] @@ -1186,7 +953,7 @@ namespace Microsoft.FSharp.Collections source |> compose { new SeqFactory<'T,'U>() with member __.Create _ _ next = upcast { new SeqComponentSimpleValue<'T,'V,int>(Upcast.iCompletionChaining next, -1) with - override this.ProcessNext (input:'T) : bool = + override this.ProcessNext (input:'T) : bool = this.Value <- this.Value + 1 TailCall.avoid (next.ProcessNext (f this.Value input)) } } @@ -1194,19 +961,204 @@ namespace Microsoft.FSharp.Collections source |> compose { new SeqFactory<'T,'U>() with member __.Create _ _ next = upcast { new SeqComponentSimpleValue<'T,'V,int>(Upcast.iCompletionChaining next, -1) with - override this.ProcessNext (input:'T) : bool = + override this.ProcessNext (input:'T) : bool = this.Value <- this.Value + 1 TailCall.avoid (next.ProcessNext (f.Invoke (this.Value, input))) } } [] - let choose f source = - source - |> compose (ChooseFactory f) + let inline choose (f:'T->option<'U>) (source:ISeq<'T>) : ISeq<'U> = + source |> compose { new SeqFactory<'T,'U>() with + member __.Create _ _ next = + upcast { new SeqComponentSimple<'T,'V>(Upcast.iCompletionChaining next) with + member __.ProcessNext input = + match f input with + | Some value -> TailCall.avoid (next.ProcessNext value) + | None -> false } } + + [] + let inline distinct (source:ISeq<'T>) : ISeq<'T> when 'T:equality = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { new SeqComponentSimpleValue<'T,'V,HashSet<'T>> + (Upcast.iCompletionChaining next,(HashSet<'T>(HashIdentity.Structural<'T>))) with + override this.ProcessNext (input:'T) : bool = + if this.Value.Add input then TailCall.avoid (next.ProcessNext input) + else false } } + + [] + let inline distinctBy (keyf:'T->'Key) (source:ISeq<'T>) :ISeq<'T> when 'Key:equality = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { new SeqComponentSimpleValue<'T,'V,HashSet<'Key>> + (Upcast.iCompletionChaining next,(HashSet<'Key>(HashIdentity.Structural<'Key>))) with + override this.ProcessNext (input:'T) : bool = + if this.Value.Add (keyf input) then TailCall.avoid (next.ProcessNext input) + else false } } + + [] + let inline pairwise (source:ISeq<'T>) : ISeq<'T * 'T> = + source |> compose { new SeqFactory<'T,'T * 'T>() with + member __.Create _ _ next = + upcast { new SeqComponentSimpleValue<'T,'U,Values> + ( Upcast.iCompletionChaining next + , Values + ((* isFirst = _1*) true + ,(* lastValue = _2*) Unchecked.defaultof<'T> + ) + ) with + override self.ProcessNext (input:'T) : bool = + if (*isFirst*) self.Value._1 then + self.Value._2 (*lastValue*)<- input + self.Value._1 (*isFirst*)<- false + false + else + let currentPair = self.Value._2, input + self.Value._2 (*lastValue*)<- input + TailCall.avoid (next.ProcessNext currentPair) + }} + + [] + let inline scan (folder:'State->'T->'State) (initialState: 'State) (source:ISeq<'T>) :ISeq<'State> = + source |> compose { new SeqFactory<'T,'State>() with + member __.Create _ _ next = + upcast { new SeqComponentSimpleValue<'T,'V,'State>(Upcast.iCompletionChaining next, initialState) with + override this.ProcessNext (input:'T) : bool = + this.Value <- folder this.Value input + TailCall.avoid (next.ProcessNext this.Value) } } + + + let scan_adapt (folder:OptimizedClosures.FSharpFunc<'State,'T,'State>) (initialState: 'State) (source:ISeq<'T>) :ISeq<'State> = + source |> compose { new SeqFactory<'T,'State>() with + member __.Create _ _ next = + upcast { new SeqComponentSimpleValue<'T,'V,'State>(Upcast.iCompletionChaining next, initialState) with + override this.ProcessNext (input:'T) : bool = + this.Value <- folder.Invoke(this.Value,input) + TailCall.avoid (next.ProcessNext this.Value) } } + + [] + let inline skip (skipCount:int) (source:ISeq<'T>) : ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { + new SeqComponentSimpleValue<'T,'U,int>(Upcast.iCompletionChaining next,(*count*)0) with + + override self.ProcessNext (input:'T) : bool = + if (*count*) self.Value < skipCount then + self.Value <- self.Value + 1 + false + else + TailCall.avoid (next.ProcessNext input) + + override self.OnComplete _ = + if (*count*) self.Value < skipCount then + let x = skipCount - self.Value + invalidOpFmt "{0}\ntried to skip {1} {2} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + + interface ISkipping with + member self.Skipping () = + let self = self :?> SeqComponentSimpleValue<'T,'U,int> + if (*count*) self.Value < skipCount then + self.Value <- self.Value + 1 + true + else + false + }} + + [] + let inline skipWhile (predicate:'T->bool) (source:ISeq<'T>) : ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { new SeqComponentSimpleValue<'T,'V,bool>(Upcast.iCompletionChaining next,true) with + override self.ProcessNext (input:'T) : bool = + if self.Value (*skip*) then + self.Value <- predicate input + if self.Value (*skip*) then + false + else + TailCall.avoid (next.ProcessNext input) + else + TailCall.avoid (next.ProcessNext input) }} + + [] + let inline take (takeCount:int) (source:ISeq<'T>) : ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create outOfBand pipelineIdx next = + upcast { + new SeqComponentSimpleValue<'T,'U,int>(Upcast.iCompletionChaining next,(*count*)0) with + override self.ProcessNext (input:'T) : bool = + if (*count*) self.Value < takeCount then + self.Value <- self.Value + 1 + if self.Value = takeCount then + outOfBand.StopFurtherProcessing pipelineIdx + TailCall.avoid (next.ProcessNext input) + else + outOfBand.StopFurtherProcessing pipelineIdx + false + + override this.OnComplete terminatingIdx = + if terminatingIdx < pipelineIdx && this.Value < takeCount then + let x = takeCount - this.Value + invalidOpFmt "tried to take {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + }} + + [] + let inline takeWhile (predicate:'T->bool) (source:ISeq<'T>) : ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create outOfBand pipeIdx next = + upcast { new SeqComponent<'T,'V>(Upcast.iCompletionChaining next) with + override __.ProcessNext (input:'T) : bool = + if predicate input then + TailCall.avoid (next.ProcessNext input) + else + outOfBand.StopFurtherProcessing pipeIdx + false + }} + + [] + let inline tail (source:ISeq<'T>) :ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { new SeqComponentSimpleValue<'T,'V,bool>(Upcast.iCompletionChaining next,(*first*) true) with + override self.ProcessNext (input:'T) : bool = + if (*first*) self.Value then + self.Value <- false + false + else + TailCall.avoid (next.ProcessNext input) + + override self.OnComplete _ = + if (*first*) self.Value then + invalidArg "source" (SR.GetString(SR.notEnoughElements)) + }} + + [] + let inline truncate (truncateCount:int) (source:ISeq<'T>) : ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create outOfBand pipeIdx next = + upcast { + new SeqComponentSimpleValue<'T,'U,int>(Upcast.iCompletionChaining next,(*count*)0) with + override self.ProcessNext (input:'T) : bool = + if (*count*) self.Value < truncateCount then + self.Value <- self.Value + 1 + if self.Value = truncateCount then + outOfBand.StopFurtherProcessing pipeIdx + TailCall.avoid (next.ProcessNext input) + else + outOfBand.StopFurtherProcessing pipeIdx + false + }} [] let inline indexed source = mapi (fun i x -> i,x) source + [] + let tryItem index (source:ISeq<'T>) = + if index < 0 then None else + source |> skip index |> tryHead + [] let tryPick f (source:ISeq<'T>) = source @@ -1223,7 +1175,7 @@ namespace Microsoft.FSharp.Collections [] let tryFind f (source:ISeq<'T>) = - source + source |> foreach (fun halt -> { new Folder<'T, Option<'T>> (None) with override this.ProcessNext value = @@ -1231,4 +1183,39 @@ namespace Microsoft.FSharp.Collections this.Value <- Some value halt () Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun find -> find.Value \ No newline at end of file + |> fun find -> find.Value + + [] + let inline windowed (windowSize:int) (source:ISeq<'T>) : ISeq<'T[]> = + source |> compose { new SeqFactory<'T,'T[]>() with + member __.Create outOfBand pipeIdx next = + upcast { + new SeqComponentSimpleValue<'T,'U,Values<'T[],int,int>> + ( Upcast.iCompletionChaining next + , Values<'T[],int,int> + ((*circularBuffer = _1 *) Array.zeroCreateUnchecked windowSize + ,(* idx = _2 *) 0 + ,(* priming = _3 *) windowSize-1 + ) + ) with + override self.ProcessNext (input:'T) : bool = + self.Value._1.[(* idx *)self.Value._2] <- input + + self.Value._2 <- (* idx *)self.Value._2 + 1 + if (* idx *) self.Value._2 = windowSize then + self.Value._2 <- 0 + + if (* priming *) self.Value._3 > 0 then + self.Value._3 <- self.Value._3 - 1 + false + else + if windowSize < 32 then + let window :'T [] = Array.init windowSize (fun i -> self.Value._1.[((* idx *)self.Value._2+i) % windowSize]: 'T) + TailCall.avoid (next.ProcessNext window) + else + let window = Array.zeroCreateUnchecked windowSize + Array.Copy((*circularBuffer*)self.Value._1, (* idx *)self.Value._2, window, 0, windowSize - (* idx *)self.Value._2) + Array.Copy((*circularBuffer*)self.Value._1, 0, window, windowSize - (* idx *)self.Value._2, (* idx *)self.Value._2) + TailCall.avoid (next.ProcessNext window) + + }} diff --git a/src/fsharp/FSharp.Core/seqcomposer.fsi b/src/fsharp/FSharp.Core/seqcomposer.fsi index c9bdf2fdb3e..391c67566cb 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fsi +++ b/src/fsharp/FSharp.Core/seqcomposer.fsi @@ -10,7 +10,7 @@ namespace Microsoft.FSharp.Collections [] module Composer = - module Core = + module Core = /// PipeIdx denotes the index of the element within the pipeline. 0 denotes the /// source of the chain. type PipeIdx = int @@ -20,7 +20,7 @@ namespace Microsoft.FSharp.Collections /// provides it's own OnComplete and OnDispose function which should be used to handle /// a particular consumers cleanup. type ICompletionChaining = - /// OnComplete is used to determine if the object has been processed correctly, + /// OnComplete is used to determine if the object has been processed correctly, /// and possibly throw exceptions to denote incorrect application (i.e. such as a Take /// operation which didn't have a source at least as large as was required). It is /// not called in the case of an exception being thrown whilst the stream is still @@ -74,6 +74,7 @@ namespace Microsoft.FSharp.Collections type SeqFactory<'T,'U> = new : unit -> SeqFactory<'T,'U> abstract PipeIdx : PipeIdx + default PipeIdx : PipeIdx abstract member Create : IOutOfBand -> PipeIdx -> Consumer<'U,'V> -> Consumer<'T,'V> type ISeq<'T> = @@ -96,26 +97,6 @@ namespace Microsoft.FSharp.Collections second: SeqFactory<'U,'V> -> SeqFactory<'T,'V> end - and ChooseFactory<'T,'U> = - class - inherit SeqFactory<'T,'U> - new : filter:('T -> 'U option) -> ChooseFactory<'T,'U> - end - and DistinctFactory<'T when 'T : equality> = - class - inherit SeqFactory<'T,'T> - new : unit -> DistinctFactory<'T> - end - and DistinctByFactory<'T,'Key when 'Key : equality> = - class - inherit SeqFactory<'T,'T> - new : keyFunction:('T -> 'Key) -> DistinctByFactory<'T,'Key> - end - and ExceptFactory<'T when 'T : equality> = - class - inherit SeqFactory<'T,'T> - new : itemsToExclude:seq<'T> -> ExceptFactory<'T> - end and IdentityFactory<'T> = class inherit SeqFactory<'T,'T> @@ -151,52 +132,6 @@ namespace Microsoft.FSharp.Collections input2:IEnumerable<'Second> -> Mapi2Factory<'First,'Second,'U> end - and PairwiseFactory<'T> = - class - inherit SeqFactory<'T,('T * 'T)> - new : unit -> PairwiseFactory<'T> - end - and ScanFactory<'T,'State> = - class - inherit SeqFactory<'T,'State> - new : folder:('State -> 'T -> 'State) * initialState:'State -> - ScanFactory<'T,'State> - end - and SkipFactory<'T> = - class - inherit SeqFactory<'T,'T> - new : count:int * notEnoughElements:(string->array->unit) -> SkipFactory<'T> - end - and SkipWhileFactory<'T> = - class - inherit SeqFactory<'T,'T> - new : predicate:('T -> bool) -> SkipWhileFactory<'T> - end - and TakeWhileFactory<'T> = - class - inherit SeqFactory<'T,'T> - new : predicate:('T -> bool) -> TakeWhileFactory<'T> - end - and TakeFactory<'T> = - class - inherit SeqFactory<'T,'T> - new : count:int -> TakeFactory<'T> - end - and TailFactory<'T> = - class - inherit SeqFactory<'T,'T> - new : unit -> TailFactory<'T> - end - and TruncateFactory<'T> = - class - inherit SeqFactory<'T,'T> - new : count:int -> TruncateFactory<'T> - end - and WindowedFactory<'T> = - class - inherit SeqFactory<'T,'T []> - new : windowSize:int -> WindowedFactory<'T> - end and ISkipping = interface abstract member Skipping : unit -> bool @@ -223,34 +158,6 @@ namespace Microsoft.FSharp.Collections new : next:ICompletionChaining -> SeqComponent<'T,'U> end - - and Choose<'T,'U,'V> = - class - inherit SeqComponent<'T,'V> - new : choose:('T -> 'U option) * next: Consumer<'U,'V> -> - Choose<'T,'U,'V> - override ProcessNext : input:'T -> bool - end - and Distinct<'T,'V when 'T : equality> = - class - inherit SeqComponent<'T,'V> - new : next: Consumer<'T,'V> -> Distinct<'T,'V> - override ProcessNext : input:'T -> bool - end - and DistinctBy<'T,'Key,'V when 'Key : equality> = - class - inherit SeqComponent<'T,'V> - new : keyFunction:('T -> 'Key) * next: Consumer<'T,'V> -> - DistinctBy<'T,'Key,'V> - override ProcessNext : input:'T -> bool - end - and Except<'T,'V when 'T : equality> = - class - inherit SeqComponent<'T,'V> - new : itemsToExclude:seq<'T> * next: Consumer<'T,'V> -> - Except<'T,'V> - override ProcessNext : input:'T -> bool - end and Map2First<'First,'Second,'U,'V> = class inherit SeqComponent<'First,'V> @@ -296,76 +203,6 @@ namespace Microsoft.FSharp.Collections override OnDispose : unit -> unit override ProcessNext : input:'First -> bool end - and Pairwise<'T,'V> = - class - inherit SeqComponent<'T,'V> - new : next: Consumer<('T * 'T),'V> -> - Pairwise<'T,'V> - override ProcessNext : input:'T -> bool - end - and Scan<'T,'State,'V> = - class - inherit SeqComponent<'T,'V> - new : folder:('State -> 'T -> 'State) * initialState:'State * - next: Consumer<'State,'V> -> - Scan<'T,'State,'V> - override ProcessNext : input:'T -> bool - end - and Skip<'T,'V> = - class - inherit SeqComponent<'T,'V> - interface ISkipping - new : skipCount:int * exceptionOnNotEnoughElements:(string->array->unit) * next: Consumer<'T,'V> -> - Skip<'T,'V> - override OnComplete : PipeIdx -> unit - override ProcessNext : input:'T -> bool - end - and SkipWhile<'T,'V> = - class - inherit SeqComponent<'T,'V> - new : predicate:('T -> bool) * next: Consumer<'T,'V> -> - SkipWhile<'T,'V> - override ProcessNext : input:'T -> bool - end - and Take<'T,'V> = - class - inherit Truncate<'T,'V> - new : takeCount:int * outOfBand: IOutOfBand * - next: Consumer<'T,'V> * pipelineIdx:int -> - Take<'T,'V> - override OnComplete : terminatingIdx: PipeIdx -> unit - end - and TakeWhile<'T,'V> = - class - inherit SeqComponent<'T,'V> - new : predicate:('T -> bool) * outOfBand: IOutOfBand * - next: Consumer<'T,'V> * pipeIdx:int -> - TakeWhile<'T,'V> - override ProcessNext : input:'T -> bool - end - and Tail<'T,'V> = - class - inherit SeqComponent<'T,'V> - new : next: Consumer<'T,'V> -> Tail<'T,'V> - override OnComplete : PipeIdx -> unit - override ProcessNext : input:'T -> bool - end - and Truncate<'T,'V> = - class - inherit SeqComponent<'T,'V> - new : truncateCount:int * outOfBand: IOutOfBand * - next: Consumer<'T,'V> * pipeIdx:int -> - Truncate<'T,'V> - override ProcessNext : input:'T -> bool - member Count : int - end - and Windowed<'T,'V> = - class - inherit SeqComponent<'T,'V> - new : windowSize:int * next: Consumer<'T [],'V> -> - Windowed<'T,'V> - override ProcessNext : input:'T -> bool - end type SeqProcessNextStates = | InProcess = 0 | NotStarted = 1 @@ -617,57 +454,100 @@ namespace Microsoft.FSharp.Collections EnumerableDecider<'T> end end - [] + + [] val toComposer : source:seq<'T> -> ISeq<'T> - val inline foreach : - f:((unit -> unit) -> 'a) -> source: ISeq<'b> -> 'a - when 'a :> Consumer<'b,'b> - [] + + val inline foreach : f:((unit -> unit) -> 'a) -> source: ISeq<'b> -> 'a when 'a :> Consumer<'b,'b> + + [] val empty<'T> : ISeq<'T> - [] - val unfold : - generator:('State -> ('T * 'State) option) -> - state:'State -> ISeq<'T> - [] + + [] + val unfold : generator:('State -> ('T * 'State) option) -> state:'State -> ISeq<'T> + + [] val initInfinite : f:(int -> 'T) -> ISeq<'T> - [] + + [] val init : count:int -> f:(int -> 'T) -> ISeq<'T> - [] + + [] val iter : f:('T -> unit) -> source: ISeq<'T> -> unit - [] + + [] val tryHead : source: ISeq<'T> -> 'T option - [] - val tryItem : i:int -> source: ISeq<'T> -> 'T option - [] + + [] val iteri : f:(int -> 'T -> unit) -> source: ISeq<'T> -> unit - [] + + [] + val inline except : itemsToExclude:seq<'T> -> source:ISeq<'T> -> ISeq<'T> when 'T:equality + + [] val exists : f:('T -> bool) -> source: ISeq<'T> -> bool - [] - val inline contains : - element:'T -> source: ISeq<'T> -> bool when 'T : equality - [] + + [] + val inline contains : element:'T -> source: ISeq<'T> -> bool when 'T : equality + + [] val forall : f:('T -> bool) -> source: ISeq<'T> -> bool - + [] val inline filter : f:('T -> bool) -> source: ISeq<'T> -> ISeq<'T> [] val inline map : f:('T -> 'U) -> source: ISeq<'T> -> ISeq<'U> - - [] + + [] val inline mapi : f:(int->'a->'b) -> source: ISeq<'a> -> ISeq<'b> val mapi_adapt : f:OptimizedClosures.FSharpFunc -> source: ISeq<'a> -> ISeq<'b> - [] - val choose : f:('a->option<'b>) -> source: ISeq<'a> -> ISeq<'b> + [] + val inline choose : f:('a->option<'b>) -> source: ISeq<'a> -> ISeq<'b> - [] + [] + val inline distinct : source: ISeq<'T> -> ISeq<'T> when 'T:equality + + [] + val inline distinctBy : keyf:('T->'Key) -> source: ISeq<'T> -> ISeq<'T> when 'Key:equality + + [] + val inline pairwise : source:ISeq<'T> -> ISeq<'T * 'T> + + [] + val inline scan : folder:('State->'T->'State) -> initialState:'State -> source:ISeq<'T> -> ISeq<'State> + + [] + val inline skip : skipCount:int -> source:ISeq<'T> -> ISeq<'T> + + [] + val inline skipWhile : predicate:('T->bool) -> source:ISeq<'T> -> ISeq<'T> + + [] + val inline take : takeCount:int -> source:ISeq<'T> -> ISeq<'T> + + [] + val inline takeWhile : predicate:('T->bool) -> source:ISeq<'T> -> ISeq<'T> + + [] + val inline tail : source:ISeq<'T> -> ISeq<'T> + + [] + val inline truncate : truncateCount:int -> source:ISeq<'T> -> ISeq<'T> + + [] val inline indexed : source: ISeq<'a> -> ISeq - [] - val tryPick : - f:('T -> 'U option) -> source: ISeq<'T> -> Option<'U> - [] + [] + val tryItem : index:int -> source: ISeq<'T> -> 'T option + + [] + val tryPick : f:('T -> 'U option) -> source: ISeq<'T> -> Option<'U> + + [] val tryFind : f:('T -> bool) -> source: ISeq<'T> -> Option<'T> + [] + val inline windowed : windowSize:int -> source:ISeq<'T> -> ISeq<'T[]> From 8f8e2808b9139bb5c6b054d017d873c003e1fb29 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Sat, 10 Dec 2016 20:04:23 +1100 Subject: [PATCH 54/59] Simplified OnComplete/OnDispose - Removed Default implementations - Renamed methods on ICompletionChain - Simplied defined hierarch make choosing correct level to implement easier --- src/fsharp/FSharp.Core/seq.fs | 18 +- src/fsharp/FSharp.Core/seqcomposer.fs | 229 +++++++++++++------------ src/fsharp/FSharp.Core/seqcomposer.fsi | 133 ++++++++------ 3 files changed, 208 insertions(+), 172 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 6edb97f3110..c21ed8cf977 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -328,7 +328,7 @@ namespace Microsoft.FSharp.Collections source |> foreach (fun _ -> - { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Core.FolderWithOnComplete<'T, Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -374,7 +374,7 @@ namespace Microsoft.FSharp.Collections source1 |> foreach (fun halt -> - { new Composer.Core.Folder<'T,int> (0) with + { new Composer.Core.FolderWithOnComplete<'T,int> (0) with override this.ProcessNext value = if not (e2.MoveNext()) then this.Value <- 1 @@ -740,7 +740,7 @@ namespace Microsoft.FSharp.Collections let inline average (source: seq< ^a>) : ^a = source |> foreach (fun _ -> - { new Composer.Core.Folder<'a, Composer.Core.Values<'a, int>> (Composer.Core.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + { new Composer.Core.FolderWithOnComplete<'a, Composer.Core.Values<'a, int>> (Composer.Core.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 value this.Value._2 <- this.Value._2 + 1 @@ -755,7 +755,7 @@ namespace Microsoft.FSharp.Collections let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = source |> foreach (fun _ -> - { new Composer.Core.Folder<'T,Composer.Core.Values<'U, int>> (Composer.Core.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + { new Composer.Core.FolderWithOnComplete<'T,Composer.Core.Values<'U, int>> (Composer.Core.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with override this.ProcessNext value = this.Value._1 <- Checked.(+) this.Value._1 (f value) this.Value._2 <- this.Value._2 + 1 @@ -775,7 +775,7 @@ namespace Microsoft.FSharp.Collections let inline min (source: seq<_>) = source |> foreach (fun _ -> - { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Core.FolderWithOnComplete<'T,Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -794,7 +794,7 @@ namespace Microsoft.FSharp.Collections let inline minBy (f : 'T -> 'U) (source: seq<'T>) : 'T = source |> foreach (fun _ -> - { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + { new Composer.Core.FolderWithOnComplete<'T,Composer.Core.Values> (Composer.Core.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with override this.ProcessNext value = match this.Value._1, f value with | true, valueU -> @@ -833,7 +833,7 @@ namespace Microsoft.FSharp.Collections let inline max (source: seq<_>) = source |> foreach (fun _ -> - { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with + { new Composer.Core.FolderWithOnComplete<'T,Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false @@ -852,7 +852,7 @@ namespace Microsoft.FSharp.Collections let inline maxBy (f : 'T -> 'U) (source: seq<'T>) : 'T = source |> foreach (fun _ -> - { new Composer.Core.Folder<'T,Composer.Core.Values> (Composer.Core.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + { new Composer.Core.FolderWithOnComplete<'T,Composer.Core.Values> (Composer.Core.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with override this.ProcessNext value = match this.Value._1, f value with | true, valueU -> @@ -985,7 +985,7 @@ namespace Microsoft.FSharp.Collections let exactlyOne (source : seq<_>) = source |> foreach (fun halt -> - { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values(true, Unchecked.defaultof<'T>, false)) with + { new Composer.Core.FolderWithOnComplete<'T, Composer.Core.Values> (Composer.Core.Values(true, Unchecked.defaultof<'T>, false)) with override this.ProcessNext value = if this.Value._1 then this.Value._1 <- false diff --git a/src/fsharp/FSharp.Core/seqcomposer.fs b/src/fsharp/FSharp.Core/seqcomposer.fs index 3026661ab3b..155343fff88 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fs +++ b/src/fsharp/FSharp.Core/seqcomposer.fs @@ -20,65 +20,105 @@ namespace Microsoft.FSharp.Collections open IEnumerator module Core = - type PipeIdx = int + [] + type NoValue = struct end - type ICompletionChaining = - abstract OnComplete : stopTailCall:byref * PipeIdx -> unit - abstract OnDispose : stopTailCall:byref -> unit + [] + type Values<'a,'b> = + val mutable _1 : 'a + val mutable _2 : 'b + + new (a:'a, b: 'b) = { _1 = a; _2 = b } + + [] + type Values<'a,'b,'c> = + val mutable _1 : 'a + val mutable _2 : 'b + val mutable _3 : 'c + + new (a:'a, b:'b, c:'c) = { _1 = a; _2 = b; _3 = c } + + type PipeIdx = int type IOutOfBand = abstract StopFurtherProcessing : PipeIdx -> unit + type ICompletionChain = + abstract ChainComplete : stopTailCall:byref * PipeIdx -> unit + abstract ChainDispose : stopTailCall:byref -> unit + [] type Consumer<'T,'U> () = abstract ProcessNext : input:'T -> bool - abstract OnComplete : PipeIdx -> unit - abstract OnDispose : unit -> unit + interface ICompletionChain with + member this.ChainComplete (_,_) = () + member this.ChainDispose _ = () - default __.OnComplete _ = () - default __.OnDispose () = () + [] + type ConsumerWithState<'T,'U,'Value> = + inherit Consumer<'T,'U> - interface ICompletionChaining with - member this.OnComplete (_, terminatingIdx) = - this.OnComplete terminatingIdx + val mutable Value : 'Value + + new (init) = { + Value = init + } - member this.OnDispose _ = - try this.OnDispose () - finally () + [] + type ConsumerChainedWithState<'T,'U,'Value> = + inherit ConsumerWithState<'T,'U,'Value> - [] - type Values<'a,'b> = - val mutable _1 : 'a - val mutable _2 : 'b + val private Next : ICompletionChain - new (a:'a, b: 'b) = { - _1 = a - _2 = b + new (next:ICompletionChain, init) = { + inherit ConsumerWithState<'T,'U,'Value> (init) + Next = next } - [] - type Values<'a,'b,'c> = - val mutable _1 : 'a - val mutable _2 : 'b - val mutable _3 : 'c + interface ICompletionChain with + member this.ChainComplete (stopTailCall, terminatingIdx) = + this.Next.ChainComplete (&stopTailCall, terminatingIdx) + member this.ChainDispose stopTailCall = + this.Next.ChainDispose (&stopTailCall) - new (a:'a, b:'b, c:'c) = { - _1 = a - _2 = b - _3 = c - } + [] + type ConsumerChained<'T,'U>(next:ICompletionChain) = + inherit ConsumerChainedWithState<'T,'U,NoValue>(next, Unchecked.defaultof) + + [] + type ConsumerChainedWithStateAndCleanup<'T,'U,'Value> (next, init) = + inherit ConsumerChainedWithState<'T,'U,'Value>(next, init) + + abstract OnComplete : PipeIdx -> unit + abstract OnDispose : unit -> unit + + interface ICompletionChain with + member this.ChainComplete (stopTailCall, terminatingIdx) = + this.OnComplete terminatingIdx + next.ChainComplete (&stopTailCall, terminatingIdx) + member this.ChainDispose stopTailCall = + try this.OnDispose () + finally next.ChainDispose (&stopTailCall) [] - type Folder<'T, 'U> = - inherit Consumer<'T,'T> + type ConsumerChainedWithCleanup<'T,'U>(next:ICompletionChain) = + inherit ConsumerChainedWithStateAndCleanup<'T,'U,NoValue>(next, Unchecked.defaultof) - val mutable Value : 'U + [] + type Folder<'T,'U>(init) = + inherit ConsumerWithState<'T,'T,'U>(init) - new (init) = { - inherit Consumer<'T,'T>() - Value = init - } + [] + type FolderWithOnComplete<'T, 'U>(init) = + inherit Folder<'T,'U>(init) + + abstract OnComplete : PipeIdx -> unit + + interface ICompletionChain with + member this.ChainComplete (stopTailCall, terminatingIdx) = + this.OnComplete terminatingIdx + member this.ChainDispose _ = () [] type SeqFactory<'T,'U> () = @@ -109,7 +149,7 @@ namespace Microsoft.FSharp.Collections let inline enumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) let inline enumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) let inline enumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) - let inline iCompletionChaining (t:#ICompletionChaining) : ICompletionChaining = (# "" t : ICompletionChaining #) + let inline iCompletionChain (t:#ICompletionChain) : ICompletionChain = (# "" t : ICompletionChain #) module internal Seq = type ComposedFactory<'T,'U,'V> private (first:SeqFactory<'T,'U>, second:SeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = @@ -151,38 +191,8 @@ namespace Microsoft.FSharp.Collections // and it can only do it at the start of a sequence abstract Skipping : unit -> bool - and [] SeqComponentSimple<'T,'U> (next:ICompletionChaining) = - inherit Consumer<'T,'U>() - - interface ICompletionChaining with - member this.OnComplete (stopTailCall, terminatingIdx) = - next.OnComplete (&stopTailCall, terminatingIdx) - member this.OnDispose stopTailCall = - next.OnDispose (&stopTailCall) - - and [] SeqComponentSimpleValue<'T,'U,'Value> = - inherit SeqComponentSimple<'T,'U> - - val mutable Value : 'Value - - new (next, init) = { - inherit SeqComponentSimple<'T,'U>(next) - Value = init - } - - and [] SeqComponent<'T,'U> (next:ICompletionChaining) = - inherit Consumer<'T,'U>() - - interface ICompletionChaining with - member this.OnComplete (stopTailCall, terminatingIdx) = - this.OnComplete terminatingIdx - next.OnComplete (&stopTailCall, terminatingIdx) - member this.OnDispose stopTailCall = - try this.OnDispose () - finally next.OnDispose (&stopTailCall) - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(Upcast.iCompletionChaining next) + inherit ConsumerChainedWithCleanup<'First,'V>(Upcast.iCompletionChain next) let input2 = enumerable2.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map @@ -194,11 +204,12 @@ namespace Microsoft.FSharp.Collections outOfBand.StopFurtherProcessing pipeIdx false + override __.OnComplete _ = () override __.OnDispose () = input2.Dispose () and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'Second,'V>(Upcast.iCompletionChaining next) + inherit ConsumerChainedWithCleanup<'Second,'V>(Upcast.iCompletionChain next) let input1 = enumerable1.GetEnumerator () let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map @@ -210,11 +221,12 @@ namespace Microsoft.FSharp.Collections outOfBand.StopFurtherProcessing pipeIdx false + override __.OnComplete _ = () override __.OnDispose () = input1.Dispose () and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(Upcast.iCompletionChaining next) + inherit ConsumerChainedWithCleanup<'First,'V>(Upcast.iCompletionChain next) let input2 = enumerable2.GetEnumerator () let input3 = enumerable3.GetEnumerator () @@ -227,12 +239,13 @@ namespace Microsoft.FSharp.Collections outOfBand.StopFurtherProcessing pipeIdx false + override __.OnComplete _ = () override __.OnDispose () = try input2.Dispose () finally input3.Dispose () and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit SeqComponent<'First,'V>(Upcast.iCompletionChaining next) + inherit ConsumerChainedWithCleanup<'First,'V>(Upcast.iCompletionChain next) let mutable idx = 0 let input2 = enumerable2.GetEnumerator () @@ -246,6 +259,7 @@ namespace Microsoft.FSharp.Collections outOfBand.StopFurtherProcessing pipeIdx false + override __.OnComplete _ = () override __.OnDispose () = input2.Dispose () @@ -333,11 +347,11 @@ namespace Microsoft.FSharp.Collections try executeOn pipeline consumer let mutable stopTailCall = () - (Upcast.iCompletionChaining consumer).OnComplete (&stopTailCall, pipeline.HaltedIdx) + (Upcast.iCompletionChain consumer).ChainComplete (&stopTailCall, pipeline.HaltedIdx) result finally let mutable stopTailCall = () - (Upcast.iCompletionChaining consumer).OnDispose (&stopTailCall) + (Upcast.iCompletionChain consumer).ChainDispose (&stopTailCall) module Enumerable = type Empty<'T>() = @@ -356,11 +370,11 @@ namespace Microsoft.FSharp.Collections static member Element = element [] - type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ICompletionChaining) = + type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ICompletionChain) = interface IDisposable with member __.Dispose() : unit = let mutable stopTailCall = () - seqComponent.OnDispose (&stopTailCall) + seqComponent.ChainDispose (&stopTailCall) interface IEnumerator with member this.Current : obj = box ((Upcast.enumerator this)).Current @@ -409,7 +423,7 @@ namespace Microsoft.FSharp.Collections else result.SeqState <- SeqProcessNextStates.Finished let mutable stopTailCall = () - (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) + (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -423,7 +437,7 @@ namespace Microsoft.FSharp.Collections source.Dispose () finally let mutable stopTailCall = () - (Upcast.iCompletionChaining seqComponent).OnDispose (&stopTailCall) + (Upcast.iCompletionChain seqComponent).ChainDispose (&stopTailCall) and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqFactory<'T,'U>) = inherit EnumerableBase<'U>() @@ -559,7 +573,7 @@ namespace Microsoft.FSharp.Collections else result.SeqState <- SeqProcessNextStates.Finished let mutable stopTailCall = () - (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) + (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -611,7 +625,7 @@ namespace Microsoft.FSharp.Collections | _ -> result.SeqState <- SeqProcessNextStates.Finished let mutable stopTailCall = () - (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) + (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -725,7 +739,7 @@ namespace Microsoft.FSharp.Collections else result.SeqState <- SeqProcessNextStates.Finished let mutable stopTailCall = () - (Upcast.iCompletionChaining seqComponent).OnComplete (&stopTailCall, result.HaltedIdx) + (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -888,8 +902,8 @@ namespace Microsoft.FSharp.Collections let inline except (itemsToExclude: seq<'T>) (source:ISeq<'T>) : ISeq<'T> when 'T:equality = source |> compose { new SeqFactory<'T,'T>() with member __.Create _ _ next = - upcast { new SeqComponentSimpleValue<'T,'V,Lazy>> - (Upcast.iCompletionChaining next,lazy(HashSet<'T>(itemsToExclude,HashIdentity.Structural<'T>))) with + upcast { new ConsumerChainedWithState<'T,'V,Lazy>> + (Upcast.iCompletionChain next,lazy(HashSet<'T>(itemsToExclude,HashIdentity.Structural<'T>))) with override this.ProcessNext (input:'T) : bool = if this.Value.Value.Add input then TailCall.avoid (next.ProcessNext input) else false @@ -935,7 +949,7 @@ namespace Microsoft.FSharp.Collections let inline filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = source |> compose { new SeqFactory<'T,'T>() with member __.Create _ _ next = - upcast { new SeqComponentSimple<'T,'V>(Upcast.iCompletionChaining next) with + upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with member __.ProcessNext input = if f input then TailCall.avoid (next.ProcessNext input) else false } } @@ -944,7 +958,7 @@ namespace Microsoft.FSharp.Collections let inline map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = source |> compose { new SeqFactory<'T,'U>() with member __.Create _ _ next = - upcast { new SeqComponentSimple<'T,'V>(Upcast.iCompletionChaining next) with + upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with member __.ProcessNext input = TailCall.avoid (next.ProcessNext (f input)) } } @@ -952,7 +966,7 @@ namespace Microsoft.FSharp.Collections let inline mapi f source = source |> compose { new SeqFactory<'T,'U>() with member __.Create _ _ next = - upcast { new SeqComponentSimpleValue<'T,'V,int>(Upcast.iCompletionChaining next, -1) with + upcast { new ConsumerChainedWithState<'T,'V,int>(Upcast.iCompletionChain next, -1) with override this.ProcessNext (input:'T) : bool = this.Value <- this.Value + 1 TailCall.avoid (next.ProcessNext (f this.Value input)) } } @@ -960,7 +974,7 @@ namespace Microsoft.FSharp.Collections let mapi_adapt (f:OptimizedClosures.FSharpFunc<_,_,_>) source = source |> compose { new SeqFactory<'T,'U>() with member __.Create _ _ next = - upcast { new SeqComponentSimpleValue<'T,'V,int>(Upcast.iCompletionChaining next, -1) with + upcast { new ConsumerChainedWithState<'T,'V,int>(Upcast.iCompletionChain next, -1) with override this.ProcessNext (input:'T) : bool = this.Value <- this.Value + 1 TailCall.avoid (next.ProcessNext (f.Invoke (this.Value, input))) } } @@ -969,7 +983,7 @@ namespace Microsoft.FSharp.Collections let inline choose (f:'T->option<'U>) (source:ISeq<'T>) : ISeq<'U> = source |> compose { new SeqFactory<'T,'U>() with member __.Create _ _ next = - upcast { new SeqComponentSimple<'T,'V>(Upcast.iCompletionChaining next) with + upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with member __.ProcessNext input = match f input with | Some value -> TailCall.avoid (next.ProcessNext value) @@ -979,8 +993,8 @@ namespace Microsoft.FSharp.Collections let inline distinct (source:ISeq<'T>) : ISeq<'T> when 'T:equality = source |> compose { new SeqFactory<'T,'T>() with member __.Create _ _ next = - upcast { new SeqComponentSimpleValue<'T,'V,HashSet<'T>> - (Upcast.iCompletionChaining next,(HashSet<'T>(HashIdentity.Structural<'T>))) with + upcast { new ConsumerChainedWithState<'T,'V,HashSet<'T>> + (Upcast.iCompletionChain next,(HashSet<'T>(HashIdentity.Structural<'T>))) with override this.ProcessNext (input:'T) : bool = if this.Value.Add input then TailCall.avoid (next.ProcessNext input) else false } } @@ -989,8 +1003,8 @@ namespace Microsoft.FSharp.Collections let inline distinctBy (keyf:'T->'Key) (source:ISeq<'T>) :ISeq<'T> when 'Key:equality = source |> compose { new SeqFactory<'T,'T>() with member __.Create _ _ next = - upcast { new SeqComponentSimpleValue<'T,'V,HashSet<'Key>> - (Upcast.iCompletionChaining next,(HashSet<'Key>(HashIdentity.Structural<'Key>))) with + upcast { new ConsumerChainedWithState<'T,'V,HashSet<'Key>> + (Upcast.iCompletionChain next,(HashSet<'Key>(HashIdentity.Structural<'Key>))) with override this.ProcessNext (input:'T) : bool = if this.Value.Add (keyf input) then TailCall.avoid (next.ProcessNext input) else false } } @@ -999,8 +1013,8 @@ namespace Microsoft.FSharp.Collections let inline pairwise (source:ISeq<'T>) : ISeq<'T * 'T> = source |> compose { new SeqFactory<'T,'T * 'T>() with member __.Create _ _ next = - upcast { new SeqComponentSimpleValue<'T,'U,Values> - ( Upcast.iCompletionChaining next + upcast { new ConsumerChainedWithState<'T,'U,Values> + ( Upcast.iCompletionChain next , Values ((* isFirst = _1*) true ,(* lastValue = _2*) Unchecked.defaultof<'T> @@ -1021,7 +1035,7 @@ namespace Microsoft.FSharp.Collections let inline scan (folder:'State->'T->'State) (initialState: 'State) (source:ISeq<'T>) :ISeq<'State> = source |> compose { new SeqFactory<'T,'State>() with member __.Create _ _ next = - upcast { new SeqComponentSimpleValue<'T,'V,'State>(Upcast.iCompletionChaining next, initialState) with + upcast { new ConsumerChainedWithState<'T,'V,'State>(Upcast.iCompletionChain next, initialState) with override this.ProcessNext (input:'T) : bool = this.Value <- folder this.Value input TailCall.avoid (next.ProcessNext this.Value) } } @@ -1030,7 +1044,7 @@ namespace Microsoft.FSharp.Collections let scan_adapt (folder:OptimizedClosures.FSharpFunc<'State,'T,'State>) (initialState: 'State) (source:ISeq<'T>) :ISeq<'State> = source |> compose { new SeqFactory<'T,'State>() with member __.Create _ _ next = - upcast { new SeqComponentSimpleValue<'T,'V,'State>(Upcast.iCompletionChaining next, initialState) with + upcast { new ConsumerChainedWithState<'T,'V,'State>(Upcast.iCompletionChain next, initialState) with override this.ProcessNext (input:'T) : bool = this.Value <- folder.Invoke(this.Value,input) TailCall.avoid (next.ProcessNext this.Value) } } @@ -1040,7 +1054,7 @@ namespace Microsoft.FSharp.Collections source |> compose { new SeqFactory<'T,'T>() with member __.Create _ _ next = upcast { - new SeqComponentSimpleValue<'T,'U,int>(Upcast.iCompletionChaining next,(*count*)0) with + new ConsumerChainedWithStateAndCleanup<'T,'U,int>(Upcast.iCompletionChain next,(*count*)0) with override self.ProcessNext (input:'T) : bool = if (*count*) self.Value < skipCount then @@ -1049,6 +1063,7 @@ namespace Microsoft.FSharp.Collections else TailCall.avoid (next.ProcessNext input) + override self.OnDispose () = () override self.OnComplete _ = if (*count*) self.Value < skipCount then let x = skipCount - self.Value @@ -1057,7 +1072,7 @@ namespace Microsoft.FSharp.Collections interface ISkipping with member self.Skipping () = - let self = self :?> SeqComponentSimpleValue<'T,'U,int> + let self = self :?> ConsumerChainedWithState<'T,'U,int> if (*count*) self.Value < skipCount then self.Value <- self.Value + 1 true @@ -1069,7 +1084,7 @@ namespace Microsoft.FSharp.Collections let inline skipWhile (predicate:'T->bool) (source:ISeq<'T>) : ISeq<'T> = source |> compose { new SeqFactory<'T,'T>() with member __.Create _ _ next = - upcast { new SeqComponentSimpleValue<'T,'V,bool>(Upcast.iCompletionChaining next,true) with + upcast { new ConsumerChainedWithState<'T,'V,bool>(Upcast.iCompletionChain next,true) with override self.ProcessNext (input:'T) : bool = if self.Value (*skip*) then self.Value <- predicate input @@ -1085,7 +1100,7 @@ namespace Microsoft.FSharp.Collections source |> compose { new SeqFactory<'T,'T>() with member __.Create outOfBand pipelineIdx next = upcast { - new SeqComponentSimpleValue<'T,'U,int>(Upcast.iCompletionChaining next,(*count*)0) with + new ConsumerChainedWithStateAndCleanup<'T,'U,int>(Upcast.iCompletionChain next,(*count*)0) with override self.ProcessNext (input:'T) : bool = if (*count*) self.Value < takeCount then self.Value <- self.Value + 1 @@ -1096,6 +1111,7 @@ namespace Microsoft.FSharp.Collections outOfBand.StopFurtherProcessing pipelineIdx false + override this.OnDispose () = () override this.OnComplete terminatingIdx = if terminatingIdx < pipelineIdx && this.Value < takeCount then let x = takeCount - this.Value @@ -1107,7 +1123,7 @@ namespace Microsoft.FSharp.Collections let inline takeWhile (predicate:'T->bool) (source:ISeq<'T>) : ISeq<'T> = source |> compose { new SeqFactory<'T,'T>() with member __.Create outOfBand pipeIdx next = - upcast { new SeqComponent<'T,'V>(Upcast.iCompletionChaining next) with + upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with override __.ProcessNext (input:'T) : bool = if predicate input then TailCall.avoid (next.ProcessNext input) @@ -1120,7 +1136,7 @@ namespace Microsoft.FSharp.Collections let inline tail (source:ISeq<'T>) :ISeq<'T> = source |> compose { new SeqFactory<'T,'T>() with member __.Create _ _ next = - upcast { new SeqComponentSimpleValue<'T,'V,bool>(Upcast.iCompletionChaining next,(*first*) true) with + upcast { new ConsumerChainedWithStateAndCleanup<'T,'V,bool>(Upcast.iCompletionChain next,(*first*) true) with override self.ProcessNext (input:'T) : bool = if (*first*) self.Value then self.Value <- false @@ -1128,6 +1144,7 @@ namespace Microsoft.FSharp.Collections else TailCall.avoid (next.ProcessNext input) + override self.OnDispose () = () override self.OnComplete _ = if (*first*) self.Value then invalidArg "source" (SR.GetString(SR.notEnoughElements)) @@ -1138,7 +1155,7 @@ namespace Microsoft.FSharp.Collections source |> compose { new SeqFactory<'T,'T>() with member __.Create outOfBand pipeIdx next = upcast { - new SeqComponentSimpleValue<'T,'U,int>(Upcast.iCompletionChaining next,(*count*)0) with + new ConsumerChainedWithState<'T,'U,int>(Upcast.iCompletionChain next,(*count*)0) with override self.ProcessNext (input:'T) : bool = if (*count*) self.Value < truncateCount then self.Value <- self.Value + 1 @@ -1190,8 +1207,8 @@ namespace Microsoft.FSharp.Collections source |> compose { new SeqFactory<'T,'T[]>() with member __.Create outOfBand pipeIdx next = upcast { - new SeqComponentSimpleValue<'T,'U,Values<'T[],int,int>> - ( Upcast.iCompletionChaining next + new ConsumerChainedWithState<'T,'U,Values<'T[],int,int>> + ( Upcast.iCompletionChain next , Values<'T[],int,int> ((*circularBuffer = _1 *) Array.zeroCreateUnchecked windowSize ,(* idx = _2 *) 0 diff --git a/src/fsharp/FSharp.Core/seqcomposer.fsi b/src/fsharp/FSharp.Core/seqcomposer.fsi index 391c67566cb..9b66a5e49b1 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fsi +++ b/src/fsharp/FSharp.Core/seqcomposer.fsi @@ -11,64 +11,104 @@ namespace Microsoft.FSharp.Collections [] module Composer = module Core = + [] + type NoValue = struct end + + /// Values is a mutable struct. It can be embedded within the folder type + /// if two values are required for the calculation. + [] + type Values<'a,'b> = + new : a:'a * b:'b -> Values<'a,'b> + val mutable _1: 'a + val mutable _2: 'b + + /// Values is a mutable struct. It can be embedded within the folder type + /// if three values are required for the calculation. + [] + type Values<'a,'b,'c> = + new : a:'a * b:'b * c:'c -> Values<'a,'b,'c> + val mutable _1: 'a + val mutable _2: 'b + val mutable _3: 'c + /// PipeIdx denotes the index of the element within the pipeline. 0 denotes the /// source of the chain. type PipeIdx = int - /// ICompletionChaining is used to correctly handle cleaning up of the pipeline. A + type IOutOfBand = + abstract StopFurtherProcessing : PipeIdx -> unit + + /// ICompletionChain is used to correctly handle cleaning up of the pipeline. A /// base implementation is provided in Consumer, and should not be overwritten. Consumer /// provides it's own OnComplete and OnDispose function which should be used to handle /// a particular consumers cleanup. - type ICompletionChaining = + type ICompletionChain = /// OnComplete is used to determine if the object has been processed correctly, /// and possibly throw exceptions to denote incorrect application (i.e. such as a Take /// operation which didn't have a source at least as large as was required). It is /// not called in the case of an exception being thrown whilst the stream is still /// being processed. - abstract OnComplete : stopTailCall:byref*PipeIdx -> unit + abstract ChainComplete : stopTailCall:byref*PipeIdx -> unit /// OnDispose is used to cleanup the stream. It is always called at the last operation /// after the enumeration has completed. - abstract OnDispose : stopTailCall:byref -> unit - - type IOutOfBand = - abstract StopFurtherProcessing : PipeIdx -> unit + abstract ChainDispose : stopTailCall:byref -> unit /// Consumer is the base class of all elements within the pipeline [] type Consumer<'T,'U> = - interface ICompletionChaining + interface ICompletionChain new : unit -> Consumer<'T,'U> abstract member ProcessNext : input:'T -> bool - abstract member OnComplete : PipeIdx -> unit - abstract member OnDispose : unit -> unit - override OnComplete : PipeIdx -> unit - override OnDispose : unit -> unit - /// Values is a mutable struct. It can be embedded within the folder type - /// if two values are required for the calculation. - [] - type Values<'a,'b> = - new : a:'a * b:'b -> Values<'a,'b> - val mutable _1: 'a - val mutable _2: 'b + [] + type ConsumerWithState<'T,'U,'Value> = + inherit Consumer<'T,'U> + val mutable Value : 'Value + new : init:'Value -> ConsumerWithState<'T,'U,'Value> - /// Values is a mutable struct. It can be embedded within the folder type - /// if three values are required for the calculation. - [] - type Values<'a,'b,'c> = - new : a:'a * b:'b * c:'c -> Values<'a,'b,'c> - val mutable _1: 'a - val mutable _2: 'b - val mutable _3: 'c + [] + type ConsumerChainedWithState<'T,'U,'Value> = + inherit ConsumerWithState<'T,'U,'Value> + interface ICompletionChain + val private Next : ICompletionChain + new : next:ICompletionChain * init:'Value -> ConsumerChainedWithState<'T,'U,'Value> + + [] + type ConsumerChained<'T,'U> = + inherit ConsumerChainedWithState<'T,'U,NoValue> + new : next:ICompletionChain -> ConsumerChained<'T,'U> + + [] + type ConsumerChainedWithStateAndCleanup<'T,'U,'Value> = + inherit ConsumerChainedWithState<'T,'U,'Value> + interface ICompletionChain + + abstract OnComplete : PipeIdx -> unit + abstract OnDispose : unit -> unit + + new : next:ICompletionChain * init:'Value -> ConsumerChainedWithStateAndCleanup<'T,'U,'Value> + + [] + type ConsumerChainedWithCleanup<'T,'U> = + inherit ConsumerChainedWithStateAndCleanup<'T,'U,NoValue> + new : next:ICompletionChain -> ConsumerChainedWithCleanup<'T,'U> /// Folder is a base class to assist with fold-like operations. It's intended usage /// is as a base class for an object expression that will be used from within /// the ForEach function. [] - type Folder<'T,'U> = - inherit Consumer<'T,'T> - new : init:'U -> Folder<'T,'U> - val mutable Value: 'U + type Folder<'T,'Value> = + inherit ConsumerWithState<'T,'T,'Value> + new : init:'Value -> Folder<'T,'Value> + + [] + type FolderWithOnComplete<'T, 'Value> = + inherit Folder<'T,'Value> + interface ICompletionChain + + abstract OnComplete : PipeIdx -> unit + + new : init:'Value -> FolderWithOnComplete<'T,'Value> [] type SeqFactory<'T,'U> = @@ -137,30 +177,9 @@ namespace Microsoft.FSharp.Collections abstract member Skipping : unit -> bool end - and [] SeqComponentSimple<'T,'U> = - class - inherit Consumer<'T,'U> - interface ICompletionChaining - new : next:ICompletionChaining -> SeqComponentSimple<'T,'U> - end - - and [] SeqComponentSimpleValue<'T,'U,'Value> = - class - inherit SeqComponentSimple<'T,'U> - val mutable Value : 'Value - new : next:ICompletionChaining*value:'Value -> SeqComponentSimpleValue<'T,'U,'Value> - end - - and [] SeqComponent<'T,'U> = - class - inherit Consumer<'T,'U> - interface ICompletionChaining - new : next:ICompletionChaining -> - SeqComponent<'T,'U> - end and Map2First<'First,'Second,'U,'V> = class - inherit SeqComponent<'First,'V> + inherit ConsumerChainedWithCleanup<'First,'V> new : map:('First -> 'Second -> 'U) * enumerable2:IEnumerable<'Second> * outOfBand: IOutOfBand * @@ -171,7 +190,7 @@ namespace Microsoft.FSharp.Collections end and Map2Second<'First,'Second,'U,'V> = class - inherit SeqComponent<'Second,'V> + inherit ConsumerChainedWithCleanup<'Second,'V> new : map:('First -> 'Second -> 'U) * enumerable1:IEnumerable<'First> * outOfBand: IOutOfBand * @@ -182,7 +201,7 @@ namespace Microsoft.FSharp.Collections end and Map3<'First,'Second,'Third,'U,'V> = class - inherit SeqComponent<'First,'V> + inherit ConsumerChainedWithCleanup<'First,'V> new : map:('First -> 'Second -> 'Third -> 'U) * enumerable2:IEnumerable<'Second> * enumerable3:IEnumerable<'Third> * @@ -194,7 +213,7 @@ namespace Microsoft.FSharp.Collections end and Mapi2<'First,'Second,'U,'V> = class - inherit SeqComponent<'First,'V> + inherit ConsumerChainedWithCleanup<'First,'V> new : map:(int -> 'First -> 'Second -> 'U) * enumerable2:IEnumerable<'Second> * outOfBand: IOutOfBand * @@ -280,7 +299,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerator interface IDisposable new : result: Result<'T> * - seqComponent: ICompletionChaining -> + seqComponent: ICompletionChain -> EnumeratorBase<'T> end and [] EnumerableBase<'T> = From 80fc59edb2f097d7958ea2e7335de6043908e135 Mon Sep 17 00:00:00 2001 From: Jared Hester Date: Tue, 13 Dec 2016 04:25:47 +0100 Subject: [PATCH 55/59] remove parens inline fold inline sum inline sumBy & inline average inline averageBy inline min & inline minBy inline max & inline maxBy inline reduce inline tryFindIndex inline tryLast inline exactlyOne remove adapt variants inline map2, inline mapi2, & inline map3 inline iter2 & inline iteri2 inline forall2 & inline exists2 inline fold2 add cleanup to folders and cleanup to folders inline compareWith elevate composers --- src/fsharp/FSharp.Core/seq.fs | 526 ++---- src/fsharp/FSharp.Core/seqcomposer.fs | 2236 ++++++++++++++---------- src/fsharp/FSharp.Core/seqcomposer.fsi | 750 ++++---- 3 files changed, 1796 insertions(+), 1716 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index c21ed8cf977..c5adc43ac6f 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -15,7 +15,6 @@ namespace Microsoft.FSharp.Collections open Microsoft.FSharp.Collections open Microsoft.FSharp.Collections.Composer open Microsoft.FSharp.Collections.Composer.Core - open Microsoft.FSharp.Collections.Composer.Seq open Microsoft.FSharp.Primitives.Basics open Microsoft.FSharp.Collections.IEnumerator @@ -47,25 +46,25 @@ namespace Microsoft.FSharp.Collections [] let toComposer (source:seq<'T>): Composer.Core.ISeq<'T> = - Composer.Seq.toComposer source + Composer.toComposer source let inline foreach f (source:seq<_>) = - Composer.Seq.foreach f (toComposer source) + Composer.foreach f (toComposer source) let private seqFactory (createSeqComponent:#SeqFactory<_,_>) (source:seq<'T>) = match source with | :? Composer.Core.ISeq<'T> as s -> Upcast.enumerable (s.Compose createSeqComponent) - | :? array<'T> as a -> Upcast.enumerable (Composer.Seq.Array.create a createSeqComponent) - | :? list<'T> as a -> Upcast.enumerable (Composer.Seq.List.create a createSeqComponent) + | :? array<'T> as a -> Upcast.enumerable (Composer.Array.create a createSeqComponent) + | :? list<'T> as a -> Upcast.enumerable (Composer.List.create a createSeqComponent) | null -> nullArg "source" - | _ -> Upcast.enumerable (Composer.Seq.Enumerable.create source createSeqComponent) + | _ -> Upcast.enumerable (Composer.Enumerable.create source createSeqComponent) [] let delay f = mkDelayedSeq f [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> = - Composer.Seq.unfold generator state + Composer.unfold generator state |> Upcast.enumerable [] @@ -73,25 +72,26 @@ namespace Microsoft.FSharp.Collections [] let initInfinite<'T> (f:int->'T) : IEnumerable<'T> = - Composer.Seq.initInfinite f + Composer.initInfinite f |> Upcast.enumerable [] let init<'T> (count:int) (f:int->'T) : IEnumerable<'T> = - Composer.Seq.init count f + Composer.init count f |> Upcast.enumerable [] let iter f (source : seq<'T>) = - source |> toComposer |> Composer.Seq.iter f + source |> toComposer |> Composer.iter f [] let tryHead (source : seq<_>) = - source |> toComposer |> Composer.Seq.tryHead + source |> toComposer |> Composer.tryHead [] let skip count (source: seq<_>) = - source |> toComposer |> Composer.Seq.skip count |> Upcast.enumerable + source |> toComposer + |> Composer.skip (SR.GetString SR.notEnoughElements) count |> Upcast.enumerable let invalidArgumnetIndex = invalidArgFmt "index" @@ -99,71 +99,53 @@ namespace Microsoft.FSharp.Collections let item i (source : seq<'T>) = if i < 0 then invalidArgInputMustBeNonNegative "index" i else source - |> toComposer |> Composer.Seq.skip i |> Upcast.enumerable + |> toComposer |> Composer.skip (SR.GetString SR.notEnoughElements) i |> Upcast.enumerable |> tryHead - |> function + |> function | None -> invalidArgFmt "index" "{0}\nseq was short by 1 element" [|SR.GetString SR.notEnoughElements|] | Some value -> value [] let tryItem i (source:seq<'T>) = - source |> toComposer |> Composer.Seq.tryItem i + source |> toComposer |> Composer.tryItem (SR.GetString SR.notEnoughElements) i - [] + [] let nth i (source : seq<'T>) = item i source - [] + [] let iteri f (source:seq<'T>) = - source |> toComposer |> Composer.Seq.iteri f + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f + source |> toComposer |> Composer.iteri (fun idx a -> f.Invoke(idx,a)) - [] + [] let exists f (source:seq<'T>) = - source |> toComposer |> Composer.Seq.exists f + source |> toComposer |> Composer.exists f - [] + [] let inline contains element (source:seq<'T>) = - source |> toComposer |> Composer.Seq.contains element + source |> toComposer |> Composer.contains element - [] + [] let forall f (source:seq<'T>) = - source |> toComposer |> Composer.Seq.forall f + source |> toComposer |> Composer.forall f - [] - let iter2 f (source1 : seq<_>) (source2 : seq<_>) = + [] + let iter2 (f:'T->'U->unit) (source1 : seq<'T>) (source2 : seq<'U>) = + checkNonNull "source1" source1 checkNonNull "source2" source2 - - use e2 = source2.GetEnumerator() let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) + (source1|>toComposer, source2|>toComposer) + ||> Composer.iter2 (fun a b -> f.Invoke(a,b)) - source1 - |> foreach (fun halt -> - { new Composer.Core.Folder<_,_> () with - override this.ProcessNext value = - if (e2.MoveNext()) then - f.Invoke(value, e2.Current) - else - halt() - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> ignore - - [] - let iteri2 f (source1 : seq<_>) (source2 : seq<_>) = - checkNonNull "source2" source2 - use e2 = source2.GetEnumerator() + [] + let iteri2 (f:int->'T->'U->unit) (source1 : seq<_>) (source2 : seq<_>) = + checkNonNull "source1" source1 + checkNonNull "source2" source2 let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f) + (source1|>toComposer, source2|>toComposer) + ||> Composer.iteri2 (fun idx a b -> f.Invoke(idx,a,b)) - source1 - |> foreach (fun halt -> - { new Composer.Core.Folder<_,int> (0) with - override this.ProcessNext value = - if (e2.MoveNext()) then - f.Invoke(this.Value, value, e2.Current) - this.Value <- this.Value + 1 - else - halt() - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> ignore // Build an IEnumerble by wrapping/transforming iterators as they get generated. let revamp f (ie : seq<_>) = mkSeq (fun () -> f (ie.GetEnumerator())) @@ -174,45 +156,49 @@ namespace Microsoft.FSharp.Collections [] let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> = - source |> toComposer |> Composer.Seq.filter f |> Upcast.enumerable + source |> toComposer |> Composer.filter f |> Upcast.enumerable [] let where f source = filter f source - [] + [] let map<'T,'U> (f:'T->'U) (source:seq<'T>) : seq<'U> = - source |> toComposer |> Composer.Seq.map f |> Upcast.enumerable + source |> toComposer |> Composer.map f |> Upcast.enumerable - [] + [] let mapi f source = - let f' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f - source |> toComposer |> Composer.Seq.mapi_adapt f' |> Upcast.enumerable + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f + source |> toComposer |> Composer.mapi (fun idx a ->f.Invoke(idx,a)) |> Upcast.enumerable - [] - let mapi2 f source1 source2 = + [] + let mapi2 (mapfn:int->'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) = + checkNonNull "source1" source1 checkNonNull "source2" source2 - source1 |> seqFactory (Composer.Seq.Mapi2Factory (f, source2)) + let f = OptimizedClosures.FSharpFunc.Adapt mapfn + (source1|>toComposer, source2|>toComposer) + ||> Composer.mapi2 (fun idx a b ->f.Invoke(idx,a,b)) |> Upcast.enumerable - [] - let map2<'T,'U,'V> (f:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = + [] + let map2<'T,'U,'V> (mapfn:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = checkNonNull "source1" source1 - match source1 with - | :? Composer.Core.ISeq<'T> as s -> Upcast.enumerable (s.Compose (Composer.Seq.Map2FirstFactory (f, source2))) - | _ -> source2 |> seqFactory (Composer.Seq.Map2SecondFactory (f, source1)) + checkNonNull "source2" source2 + (source1|>toComposer, source2|>toComposer) + ||> Composer.map2 mapfn |> Upcast.enumerable - [] - let map3 f source1 source2 source3 = + [] + let map3 mapfn source1 source2 source3 = checkNonNull "source2" source2 checkNonNull "source3" source3 - source1 |> seqFactory (Composer.Seq.Map3Factory (f, source2, source3)) + (source1|>toComposer, source2|>toComposer, source3|>toComposer) + |||> Composer.map3 mapfn |> Upcast.enumerable [] let choose f source = - source |> toComposer |> Composer.Seq.choose f |> Upcast.enumerable + source |> toComposer |> Composer.choose f |> Upcast.enumerable [] let indexed source = - source |> toComposer |> Composer.Seq.indexed |> Upcast.enumerable + source |> toComposer |> Composer.indexed |> Upcast.enumerable [] let zip source1 source2 = @@ -229,7 +215,7 @@ namespace Microsoft.FSharp.Collections [] let tryPick f (source : seq<'T>) = - source |> toComposer |> Composer.Seq.tryPick f + source |> toComposer |> Composer.tryPick f [] let pick f source = @@ -239,7 +225,7 @@ namespace Microsoft.FSharp.Collections [] let tryFind f (source : seq<'T>) = - source |> toComposer |> Composer.Seq.tryFind f + source |> toComposer |> Composer.tryFind f [] let find f source = @@ -252,7 +238,7 @@ namespace Microsoft.FSharp.Collections if count < 0 then invalidArgInputMustBeNonNegative "count" count (* Note: don't create or dispose any IEnumerable if n = 0 *) if count = 0 then empty else - source |> toComposer |> Composer.Seq.take count |> Upcast.enumerable + source |> toComposer |> Composer.take (SR.GetString SR.notEnoughElements) count |> Upcast.enumerable [] let isEmpty (source : seq<'T>) = @@ -268,7 +254,7 @@ namespace Microsoft.FSharp.Collections [] let concat (sources:seq<#seq<'T>>) : seq<'T> = checkNonNull "sources" sources - upcast Composer.Seq.Enumerable.ConcatEnumerable sources + upcast Composer.Enumerable.ConcatEnumerable sources [] let length (source : seq<'T>) = @@ -284,64 +270,25 @@ namespace Microsoft.FSharp.Collections state <- state + 1 state - [] - let fold<'T,'State> f (x:'State) (source:seq<'T>) = + [] + let fold<'T,'State> (f:'State->'T->'State) (x:'State) (source:seq<'T>) = let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) + source |> toComposer + |> Composer.fold<'T,'State>(fun (a:'State) (b:'T) -> f.Invoke(a,b)) x + - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'T,'State> (x) with - override this.ProcessNext value = - this.Value <- f.Invoke (this.Value, value) - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun folded -> folded.Value - - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'T,'State> (x) with - override this.ProcessNext value = - this.Value <- f.Invoke (this.Value, value) - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun folded -> folded.Value - - [] + [] let fold2<'T1,'T2,'State> f (state:'State) (source1: seq<'T1>) (source2: seq<'T2>) = + checkNonNull "source1" source1 checkNonNull "source2" source2 - - use e2 = source2.GetEnumerator() let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f) + (source1 |> toComposer, source2|>toComposer) + ||> Composer.fold2(fun s a b -> f.Invoke(s,a,b)) state - source1 - |> foreach (fun halt -> - { new Composer.Core.Folder<_,'State> (state) with - override this.ProcessNext value = - if (e2.MoveNext()) then - this.Value <- f.Invoke(this.Value, value, e2.Current) - else - halt() - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun fold -> fold.Value - - [] + [] let reduce f (source : seq<'T>) = let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - - source - |> foreach (fun _ -> - { new Composer.Core.FolderWithOnComplete<'T, Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value - else - this.Value._2 <- f.Invoke (this.Value._2, value) - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - - member this.OnComplete _ = - if this.Value._1 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun reduced -> reduced.Value._2 + source |> toComposer |> Composer.reduce(fun a b -> f.Invoke(a,b)) [] let replicate count x = @@ -358,37 +305,21 @@ namespace Microsoft.FSharp.Collections checkNonNull "source1" source1 checkNonNull "source2" source2 match source1 with - | :? Composer.Seq.Enumerable.EnumerableBase<'T> as s -> s.Append source2 - | _ -> Upcast.enumerable (new Composer.Seq.Enumerable.AppendEnumerable<_>([source2; source1])) + | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Append source2 + | _ -> Upcast.enumerable (new Composer.Enumerable.AppendEnumerable<_>([source2; source1])) [] let collect f sources = map f sources |> concat - [] + [] let compareWith (f:'T -> 'T -> int) (source1 : seq<'T>) (source2: seq<'T>) = + checkNonNull "source1" source1 checkNonNull "source2" source2 - - use e2 = source2.GetEnumerator() let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) + (source1|>toComposer, source2|>toComposer) + ||> Composer.compareWith (fun a b -> f.Invoke(a,b)) - source1 - |> foreach (fun halt -> - { new Composer.Core.FolderWithOnComplete<'T,int> (0) with - override this.ProcessNext value = - if not (e2.MoveNext()) then - this.Value <- 1 - halt () - else - let c = f.Invoke (value, e2.Current) - if c <> 0 then - this.Value <- c - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - member this.OnComplete _ = - if this.Value = 0 && e2.MoveNext() then - this.Value <- -1 }) - |> fun compare -> compare.Value [] let ofList (source : 'T list) = @@ -403,7 +334,7 @@ namespace Microsoft.FSharp.Collections [] let ofArray (source : 'T array) = checkNonNull "source" source - Upcast.enumerable (Composer.Seq.Array.createId source) + Upcast.enumerable (Composer.Array.createId source) [] let toArray (source : seq<'T>) = @@ -457,15 +388,15 @@ namespace Microsoft.FSharp.Collections [] let truncate n (source: seq<'T>) = if n <= 0 then empty else - source |> toComposer |> Composer.Seq.truncate n |> Upcast.enumerable + source |> toComposer |> Composer.truncate n |> Upcast.enumerable [] let pairwise<'T> (source:seq<'T>) : seq<'T*'T> = - source |> toComposer |> Composer.Seq.pairwise |> Upcast.enumerable + source |> toComposer |> Composer.pairwise |> Upcast.enumerable [] let scan<'T,'State> (folder:'State->'T->'State) (state:'State) (source:seq<'T>) : seq<'State> = - source |> toComposer |> Composer.Seq.scan folder state |> Upcast.enumerable + source |> toComposer |> Composer.scan folder state |> Upcast.enumerable [] let tryFindBack f (source : seq<'T>) = @@ -485,19 +416,9 @@ namespace Microsoft.FSharp.Collections let res = Array.scanSubRight f arr 0 (arr.Length - 1) acc res :> seq<_>) - [] + [] let tryFindIndex p (source:seq<_>) = - source - |> foreach (fun halt -> - { new Composer.Core.Folder<'T, Composer.Core.Values, int>> (Composer.Core.Values<_,_>(None, 0)) with - override this.ProcessNext value = - if p value then - this.Value._1 <- Some(this.Value._2) - halt () - else - this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun tried -> tried.Value._1 + source |> toComposer |> Composer.tryFindIndex p [] let findIndex p (source:seq<_>) = @@ -520,7 +441,7 @@ namespace Microsoft.FSharp.Collections let windowed windowSize (source: seq<_>) = if windowSize <= 0 then invalidArgFmt "windowSize" "{0}\nwindowSize = {1}" [|SR.GetString SR.inputMustBePositive; windowSize|] - source |> toComposer |> Composer.Seq.windowed windowSize |> Upcast.enumerable + source |> toComposer |> Composer.windowed windowSize |> Upcast.enumerable [] let cache (source : seq<'T>) = @@ -638,11 +559,11 @@ namespace Microsoft.FSharp.Collections [] let distinct source = - source |> toComposer |> Composer.Seq.distinct |> Upcast.enumerable + source |> toComposer |> Composer.distinct |> Upcast.enumerable [] let distinctBy keyf source = - source |> toComposer |> Composer.Seq.distinctBy keyf |> Upcast.enumerable + source |> toComposer |> Composer.distinctBy keyf |> Upcast.enumerable [] let sortBy keyf source = @@ -651,7 +572,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceBy keyf array array - Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedSort) + Upcast.enumerable (Composer.Array.createDelayedId delayedSort) [] let sort source = @@ -660,7 +581,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlace array array - Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedSort) + Upcast.enumerable (Composer.Array.createDelayedId delayedSort) [] let sortWith f source = @@ -669,7 +590,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.stableSortInPlaceWith f array array - Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedSort) + Upcast.enumerable (Composer.Array.createDelayedId delayedSort) [] let inline sortByDescending keyf source = @@ -716,102 +637,29 @@ namespace Microsoft.FSharp.Collections then mkDelayedSeq (fun () -> countByValueType keyf source) else mkDelayedSeq (fun () -> countByRefType keyf source) - [] + [] let inline sum (source:seq<'a>) : 'a = - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'a,'a> (LanguagePrimitives.GenericZero) with - override this.ProcessNext value = - this.Value <- Checked.(+) this.Value value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun sum -> sum.Value - - [] + source |> toComposer |> Composer.sum + + [] let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U = - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with - override this.ProcessNext value = - this.Value <- Checked.(+) this.Value (f value) - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun sum -> sum.Value - - [] + source |> toComposer |> Composer.sumBy f + + [] let inline average (source: seq< ^a>) : ^a = - source - |> foreach (fun _ -> - { new Composer.Core.FolderWithOnComplete<'a, Composer.Core.Values<'a, int>> (Composer.Core.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with - override this.ProcessNext value = - this.Value._1 <- Checked.(+) this.Value._1 value - this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - - member this.OnComplete _ = - if this.Value._2 = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) - |> fun total -> LanguagePrimitives.DivideByInt< ^a> total.Value._1 total.Value._2 - - [] + source |> toComposer |> Composer.average + + [] let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U = - source - |> foreach (fun _ -> - { new Composer.Core.FolderWithOnComplete<'T,Composer.Core.Values<'U, int>> (Composer.Core.Values<_,_>(LanguagePrimitives.GenericZero, 0)) with - override this.ProcessNext value = - this.Value._1 <- Checked.(+) this.Value._1 (f value) - this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - - member this.OnComplete _ = - if this.Value._2 = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) - |> fun total -> LanguagePrimitives.DivideByInt< ^U> total.Value._1 total.Value._2 - - member this.OnComplete _ = - if this.Value._2 = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) - |> fun total -> LanguagePrimitives.DivideByInt< ^U> total.Value._1 total.Value._2 - - [] - let inline min (source: seq<_>) = - source - |> foreach (fun _ -> - { new Composer.Core.FolderWithOnComplete<'T,Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value - elif value < this.Value._2 then - this.Value._2 <- value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + source |> toComposer |> Composer.averageBy f - member this.OnComplete _ = - if this.Value._1 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun min -> min.Value._2 - - [] - let inline minBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - source - |> foreach (fun _ -> - { new Composer.Core.FolderWithOnComplete<'T,Composer.Core.Values> (Composer.Core.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - match this.Value._1, f value with - | true, valueU -> - this.Value._1 <- false - this.Value._2 <- valueU - this.Value._3 <- value - | false, valueU when valueU < this.Value._2 -> - this.Value._2 <- valueU - this.Value._3 <- value - | _ -> () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - - member this.OnComplete _ = - if this.Value._1 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun min -> min.Value._3 + [] + let inline min (source: seq<'T>): 'T when 'T : comparison = + source |> toComposer |> Composer.min + + [] + let inline minBy (projection: 'T -> 'U when 'U:comparison) (source: seq<'T>) : 'T = + source |> toComposer |> Composer.minBy projection (* [] let inline minValBy (f : 'T -> 'U) (source: seq<'T>) : 'U = @@ -829,47 +677,13 @@ namespace Microsoft.FSharp.Collections acc *) - [] - let inline max (source: seq<_>) = - source - |> foreach (fun _ -> - { new Composer.Core.FolderWithOnComplete<'T,Composer.Core.Values> (Composer.Core.Values<_,_>(true, Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value - elif value > this.Value._2 then - this.Value._2 <- value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + [] + let inline max (source: seq<'T>) = + source |> toComposer |> Composer.max - member this.OnComplete _ = - if this.Value._1 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun max -> max.Value._2 - - [] - let inline maxBy (f : 'T -> 'U) (source: seq<'T>) : 'T = - source - |> foreach (fun _ -> - { new Composer.Core.FolderWithOnComplete<'T,Composer.Core.Values> (Composer.Core.Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - match this.Value._1, f value with - | true, valueU -> - this.Value._1 <- false - this.Value._2 <- valueU - this.Value._3 <- value - | false, valueU when valueU > this.Value._2 -> - this.Value._2 <- valueU - this.Value._3 <- value - | _ -> () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - - member this.OnComplete _ = - if this.Value._1 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun min -> min.Value._3 + [] + let inline maxBy (projection: 'T -> 'U) (source: seq<'T>) : 'T = + source |> toComposer |> Composer.maxBy projection (* [] @@ -890,66 +704,29 @@ namespace Microsoft.FSharp.Collections *) [] let takeWhile predicate (source: seq<_>) = - source |> toComposer |> Composer.Seq.takeWhile predicate |> Upcast.enumerable + source |> toComposer |> Composer.takeWhile predicate |> Upcast.enumerable [] let skipWhile predicate (source: seq<_>) = - source |> toComposer |> Composer.Seq.skipWhile predicate |> Upcast.enumerable + source |> toComposer |> Composer.skipWhile predicate |> Upcast.enumerable - [] + [] let forall2 p (source1: seq<_>) (source2: seq<_>) = + checkNonNull "source1" source1 checkNonNull "source2" source2 + let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt p + (source1|>toComposer, source2|>toComposer) + ||> Composer.forall2 (fun a b -> p.Invoke(a,b)) - use e2 = source2.GetEnumerator() - let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(p) - - source1 - |> foreach (fun halt -> - { new Composer.Core.Folder<_,bool> (true) with - override this.ProcessNext value = - if (e2.MoveNext()) then - if not (p.Invoke(value, e2.Current)) then - this.Value <- false - halt() - else - halt() - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun all -> all.Value - - [] + [] let exists2 p (source1: seq<_>) (source2: seq<_>) = + checkNonNull "source1" source1 checkNonNull "source2" source2 + let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt p + (source1|>toComposer, source2|>toComposer) + ||> Composer.exists2 (fun a b -> p.Invoke(a,b)) - use e2 = source2.GetEnumerator() - let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(p) - - source1 - |> foreach (fun halt -> - { new Composer.Core.Folder<_,bool> (false) with - override this.ProcessNext value = - if (e2.MoveNext()) then - if p.Invoke(value, e2.Current) then - this.Value <- true - halt() - else - halt() - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun exists -> exists.Value - - source1 - |> foreach (fun halt -> - { new Composer.Core.Folder<_,bool> (false) with - override this.ProcessNext value = - if (e2.MoveNext()) then - if p.Invoke(value, e2.Current) then - this.Value <- true - halt() - else - halt() - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun exists -> exists.Value - - [] + [] let head (source : seq<_>) = match tryHead source with | None -> invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString @@ -957,23 +734,11 @@ namespace Microsoft.FSharp.Collections [] let tail (source: seq<'T>) = - source |> toComposer |> Composer.Seq.tail |> Upcast.enumerable + source |> toComposer |> Composer.tail (SR.GetString SR.notEnoughElements) |> Upcast.enumerable - [] + [] let tryLast (source : seq<_>) = - source - |> foreach (fun _ -> - { new Composer.Core.Folder<'T, Composer.Core.Values> (Composer.Core.Values(true, Unchecked.defaultof<'T>)) with - override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun tried -> - if tried.Value._1 then - None - else - Some tried.Value._2 + source |> toComposer |> Composer.tryLast [] let last (source : seq<_>) = @@ -981,26 +746,9 @@ namespace Microsoft.FSharp.Collections | None -> invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString | Some x -> x - [] + [] let exactlyOne (source : seq<_>) = - source - |> foreach (fun halt -> - { new Composer.Core.FolderWithOnComplete<'T, Composer.Core.Values> (Composer.Core.Values(true, Unchecked.defaultof<'T>, false)) with - override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value - else - this.Value._3 <- true - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - - member this.OnComplete _ = - if this.Value._1 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - elif this.Value._3 then - invalidArg "source" (SR.GetString(SR.inputSequenceTooLong)) }) - |> fun one -> one.Value._2 + source |> toComposer |> Composer.exactlyOne (SR.GetString(SR.inputSequenceTooLong)) member this.OnComplete _ = if this.Value._1 then @@ -1016,7 +764,7 @@ namespace Microsoft.FSharp.Collections let array = source |> toArray Array.Reverse array array - Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedReverse) + Upcast.enumerable (Composer.Array.createDelayedId delayedReverse) [] let permute f (source:seq<_>) = @@ -1025,7 +773,7 @@ namespace Microsoft.FSharp.Collections source |> toArray |> Array.permute f - Upcast.enumerable (Composer.Seq.Array.createDelayedId delayedPermute) + Upcast.enumerable (Composer.Array.createDelayedId delayedPermute) [] let mapFold<'T,'State,'Result> (f: 'State -> 'T -> 'Result * 'State) acc source = @@ -1044,7 +792,7 @@ namespace Microsoft.FSharp.Collections let except (itemsToExclude: seq<'T>) (source: seq<'T>) = checkNonNull "itemsToExclude" itemsToExclude if isEmpty itemsToExclude then source else - source |> toComposer |> Composer.Seq.except itemsToExclude |> Upcast.enumerable + source |> toComposer |> Composer.except itemsToExclude |> Upcast.enumerable [] let chunkBySize chunkSize (source : seq<_>) = diff --git a/src/fsharp/FSharp.Core/seqcomposer.fs b/src/fsharp/FSharp.Core/seqcomposer.fs index 155343fff88..bbc6ab3cdf9 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fs +++ b/src/fsharp/FSharp.Core/seqcomposer.fs @@ -86,7 +86,7 @@ namespace Microsoft.FSharp.Collections type ConsumerChained<'T,'U>(next:ICompletionChain) = inherit ConsumerChainedWithState<'T,'U,NoValue>(next, Unchecked.defaultof) - [] + [] type ConsumerChainedWithStateAndCleanup<'T,'U,'Value> (next, init) = inherit ConsumerChainedWithState<'T,'U,'Value>(next, init) @@ -151,1088 +151,1420 @@ namespace Microsoft.FSharp.Collections let inline enumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) let inline iCompletionChain (t:#ICompletionChain) : ICompletionChain = (# "" t : ICompletionChain #) - module internal Seq = - type ComposedFactory<'T,'U,'V> private (first:SeqFactory<'T,'U>, second:SeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = - inherit SeqFactory<'T,'V>() - override __.PipeIdx = - secondPipeIdx + type ComposedFactory<'T,'U,'V> private (first:SeqFactory<'T,'U>, second:SeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = + inherit SeqFactory<'T,'V>() - override this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'V,'W>) : Consumer<'T,'W> = - first.Create outOfBand pipeIdx (second.Create outOfBand secondPipeIdx next) + override __.PipeIdx = + secondPipeIdx - static member Combine (first:SeqFactory<'T,'U>) (second:SeqFactory<'U,'V>) : SeqFactory<'T,'V> = - upcast ComposedFactory(first, second, first.PipeIdx+1) + override this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'V,'W>) : Consumer<'T,'W> = + first.Create outOfBand pipeIdx (second.Create outOfBand secondPipeIdx next) - and IdentityFactory<'T> () = - inherit SeqFactory<'T,'T> () - static let singleton : SeqFactory<'T,'T> = upcast (IdentityFactory<'T>()) - override __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next - static member Instance = singleton + static member Combine (first:SeqFactory<'T,'U>) (second:SeqFactory<'U,'V>) : SeqFactory<'T,'V> = + upcast ComposedFactory(first, second, first.PipeIdx+1) - and Map2FirstFactory<'First,'Second,'U> (map:'First->'Second->'U, input2:IEnumerable<'Second>) = - inherit SeqFactory<'First,'U> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map2First (map, input2, outOfBand, next, pipeIdx) + and IdentityFactory<'T> () = + inherit SeqFactory<'T,'T> () + static let singleton : SeqFactory<'T,'T> = upcast (IdentityFactory<'T>()) + override __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next + static member Instance = singleton - and Map2SecondFactory<'First,'Second,'U> (map:'First->'Second->'U, input1:IEnumerable<'First>) = - inherit SeqFactory<'Second,'U> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'Second,'V> = upcast Map2Second (map, input1, outOfBand, next, pipeIdx) + and ISkipping = + // Seq.init(Infinite)? lazily uses Current. The only Composer component that can do that is Skip + // and it can only do it at the start of a sequence + abstract Skipping : unit -> bool - and Map3Factory<'First,'Second,'Third,'U> (map:'First->'Second->'Third->'U, input2:IEnumerable<'Second>, input3:IEnumerable<'Third>) = - inherit SeqFactory<'First,'U> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Map3 (map, input2, input3, outOfBand, next, pipeIdx) + type SeqProcessNextStates = + | InProcess = 0 + | NotStarted = 1 + | Finished = 2 - and Mapi2Factory<'First,'Second,'U> (map:int->'First->'Second->'U, input2:IEnumerable<'Second>) = - inherit SeqFactory<'First,'U> () - override this.Create<'V> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'U,'V>) : Consumer<'First,'V> = upcast Mapi2 (map, input2, outOfBand, next, pipeIdx) + type Result<'T>() = + let mutable haltedIdx = 0 - and ISkipping = - // Seq.init(Infinite)? lazily uses Current. The only Composer component that can do that is Skip - // and it can only do it at the start of a sequence - abstract Skipping : unit -> bool + member val Current = Unchecked.defaultof<'T> with get, set + member val SeqState = SeqProcessNextStates.NotStarted with get, set + member __.HaltedIdx = haltedIdx - and Map2First<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit ConsumerChainedWithCleanup<'First,'V>(Upcast.iCompletionChain next) + interface IOutOfBand with + member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx - let input2 = enumerable2.GetEnumerator () - let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map + // SetResult<> is used at the end of the chain of SeqComponents to assign the final value + type SetResult<'T> (result:Result<'T>) = + inherit Consumer<'T,'T>() - override __.ProcessNext (input:'First) : bool = - if input2.MoveNext () then - TailCall.avoid (next.ProcessNext (map'.Invoke (input, input2.Current))) - else - outOfBand.StopFurtherProcessing pipeIdx - false + override __.ProcessNext (input:'T) : bool = + result.Current <- input + true - override __.OnComplete _ = () - override __.OnDispose () = - input2.Dispose () + type OutOfBand() = + let mutable haltedIdx = 0 + interface IOutOfBand with member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx + member __.HaltedIdx = haltedIdx - and Map2Second<'First,'Second,'U,'V> (map:'First->'Second->'U, enumerable1:IEnumerable<'First>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit ConsumerChainedWithCleanup<'Second,'V>(Upcast.iCompletionChain next) + module ForEach = + let enumerable (enumerable:IEnumerable<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = + use enumerator = enumerable.GetEnumerator () + while (outOfBand.HaltedIdx = 0) && (enumerator.MoveNext ()) do + consumer.ProcessNext enumerator.Current |> ignore - let input1 = enumerable1.GetEnumerator () - let map' = OptimizedClosures.FSharpFunc<_,_,_>.Adapt map + let array (array:array<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = + let mutable idx = 0 + while (outOfBand.HaltedIdx = 0) && (idx < array.Length) do + consumer.ProcessNext array.[idx] |> ignore + idx <- idx + 1 + + let list (alist:list<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = + let rec iterate lst = + match outOfBand.HaltedIdx, lst with + | 0, hd :: tl -> + consumer.ProcessNext hd |> ignore + iterate tl + | _ -> () + iterate alist + + let unfold (generator:'S->option<'T*'S>) state (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = + let rec iterate current = + match outOfBand.HaltedIdx, generator current with + | 0, Some (item, next) -> + consumer.ProcessNext item |> ignore + iterate next + | _ -> () + + iterate state + + let makeIsSkipping (consumer:Consumer<'T,'U>) = + match box consumer with + | :? ISkipping as skip -> skip.Skipping + | _ -> fun () -> false + + let init f (terminatingIdx:int) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = + let mutable idx = -1 + let isSkipping = makeIsSkipping consumer + let mutable maybeSkipping = true + while (outOfBand.HaltedIdx = 0) && (idx < terminatingIdx) do + if maybeSkipping then + maybeSkipping <- isSkipping () + + if not maybeSkipping then + consumer.ProcessNext (f (idx+1)) |> ignore + + idx <- idx + 1 + + let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:SeqFactory<'T,'U>) executeOn = + let pipeline = OutOfBand() + let result = f (fun () -> (pipeline:>IOutOfBand).StopFurtherProcessing (current.PipeIdx+1)) + let consumer = current.Build pipeline result + try + executeOn pipeline consumer + let mutable stopTailCall = () + (Upcast.iCompletionChain consumer).ChainComplete (&stopTailCall, pipeline.HaltedIdx) + result + finally + let mutable stopTailCall = () + (Upcast.iCompletionChain consumer).ChainDispose (&stopTailCall) + + module Enumerable = + type Empty<'T>() = + let current () = failwith "library implementation error: Current should never be called" + interface IEnumerator<'T> with + member __.Current = current () + interface IEnumerator with + member __.Current = current () + member __.MoveNext () = false + member __.Reset (): unit = noReset () + interface IDisposable with + member __.Dispose () = () + + type EmptyEnumerators<'T>() = + static let element : IEnumerator<'T> = upcast (new Empty<'T> ()) + static member Element = element - override __.ProcessNext (input:'Second) : bool = - if input1.MoveNext () then - TailCall.avoid (next.ProcessNext (map'.Invoke (input1.Current, input))) - else - outOfBand.StopFurtherProcessing pipeIdx - false + [] + type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ICompletionChain) = + interface IDisposable with + member __.Dispose() : unit = + let mutable stopTailCall = () + seqComponent.ChainDispose (&stopTailCall) - override __.OnComplete _ = () - override __.OnDispose () = - input1.Dispose () + interface IEnumerator with + member this.Current : obj = box ((Upcast.enumerator this)).Current + member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)" + member __.Reset () : unit = noReset () - and Map3<'First,'Second,'Third,'U,'V> (map:'First->'Second->'Third->'U, enumerable2:IEnumerable<'Second>, enumerable3:IEnumerable<'Third>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit ConsumerChainedWithCleanup<'First,'V>(Upcast.iCompletionChain next) + interface IEnumerator<'T> with + member __.Current = + if result.SeqState = SeqProcessNextStates.InProcess then result.Current + else + match result.SeqState with + | SeqProcessNextStates.NotStarted -> notStarted() + | SeqProcessNextStates.Finished -> alreadyFinished() + | _ -> failwith "library implementation error: all states should have been handled" - let input2 = enumerable2.GetEnumerator () - let input3 = enumerable3.GetEnumerator () - let map' = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt map + and [] EnumerableBase<'T> () = + let derivedClassShouldImplement () = + failwith "library implementation error: derived class should implement (should be abstract)" - override __.ProcessNext (input:'First) : bool = - if input2.MoveNext () && input3.MoveNext () then - TailCall.avoid (next.ProcessNext (map'.Invoke (input, input2.Current, input3.Current))) - else - outOfBand.StopFurtherProcessing pipeIdx - false + abstract member Append : (seq<'T>) -> IEnumerable<'T> - override __.OnComplete _ = () - override __.OnDispose () = - try input2.Dispose () - finally input3.Dispose () + default this.Append source = Upcast.enumerable (AppendEnumerable [this; source]) - and Mapi2<'First,'Second,'U,'V> (map:int->'First->'Second->'U, enumerable2:IEnumerable<'Second>, outOfBand:IOutOfBand, next:Consumer<'U,'V>, pipeIdx:int) = - inherit ConsumerChainedWithCleanup<'First,'V>(Upcast.iCompletionChain next) + interface IEnumerable with + member this.GetEnumerator () : IEnumerator = + let genericEnumerable = Upcast.enumerable this + let genericEnumerator = genericEnumerable.GetEnumerator () + Upcast.enumeratorNonGeneric genericEnumerator - let mutable idx = 0 - let input2 = enumerable2.GetEnumerator () - let mapi2' = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt map + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement () - override __.ProcessNext (input:'First) : bool = - if input2.MoveNext () then - idx <- idx + 1 - TailCall.avoid (next.ProcessNext (mapi2'.Invoke (idx-1, input, input2.Current))) - else - outOfBand.StopFurtherProcessing pipeIdx - false + interface ISeq<'T> with + member __.Compose _ = derivedClassShouldImplement () + member __.ForEach _ = derivedClassShouldImplement () - override __.OnComplete _ = () - override __.OnDispose () = - input2.Dispose () + and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit EnumeratorBase<'U>(result, seqComponent) - type SeqProcessNextStates = - | InProcess = 0 - | NotStarted = 1 - | Finished = 2 + let rec moveNext () = + if (result.HaltedIdx = 0) && source.MoveNext () then + if seqComponent.ProcessNext source.Current then + true + else + moveNext () + else + result.SeqState <- SeqProcessNextStates.Finished + let mutable stopTailCall = () + (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) + false - type Result<'T>() = - let mutable haltedIdx = 0 + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext () - member val Current = Unchecked.defaultof<'T> with get, set - member val SeqState = SeqProcessNextStates.NotStarted with get, set - member __.HaltedIdx = haltedIdx + interface IDisposable with + member __.Dispose() = + try + source.Dispose () + finally + let mutable stopTailCall = () + (Upcast.iCompletionChain seqComponent).ChainDispose (&stopTailCall) - interface IOutOfBand with - member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx + and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqFactory<'T,'U>) = + inherit EnumerableBase<'U>() - // SetResult<> is used at the end of the chain of SeqComponents to assign the final value - type SetResult<'T> (result:Result<'T>) = - inherit Consumer<'T,'T>() + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Upcast.enumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Build result (SetResult<'U> result), result)) - override __.ProcessNext (input:'T) : bool = - result.Current <- input - true + interface ISeq<'U> with + member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) - type OutOfBand() = - let mutable haltedIdx = 0 - interface IOutOfBand with member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx - member __.HaltedIdx = haltedIdx + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.enumerable enumerable) - module ForEach = - let enumerable (enumerable:IEnumerable<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - use enumerator = enumerable.GetEnumerator () - while (outOfBand.HaltedIdx = 0) && (enumerator.MoveNext ()) do - consumer.ProcessNext enumerator.Current |> ignore + and ConcatEnumerator<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = + let mutable state = SeqProcessNextStates.NotStarted + let main = sources.GetEnumerator () - let array (array:array<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let mutable idx = 0 - while (outOfBand.HaltedIdx = 0) && (idx < array.Length) do - consumer.ProcessNext array.[idx] |> ignore - idx <- idx + 1 + let mutable active = EmptyEnumerators.Element - let list (alist:list<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let rec iterate lst = - match outOfBand.HaltedIdx, lst with - | 0, hd :: tl -> - consumer.ProcessNext hd |> ignore - iterate tl - | _ -> () - iterate alist - - let unfold (generator:'S->option<'T*'S>) state (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let rec iterate current = - match outOfBand.HaltedIdx, generator current with - | 0, Some (item, next) -> - consumer.ProcessNext item |> ignore - iterate next - | _ -> () + let rec moveNext () = + if active.MoveNext () then + true + elif main.MoveNext () then + active.Dispose () + active <- main.Current.GetEnumerator () + moveNext () + else + state <- SeqProcessNextStates.Finished + false - iterate state + interface IEnumerator<'T> with + member __.Current = + if state = SeqProcessNextStates.InProcess then active.Current + else + match state with + | SeqProcessNextStates.NotStarted -> notStarted() + | SeqProcessNextStates.Finished -> alreadyFinished() + | _ -> failwith "library implementation error: all states should have been handled" - let makeIsSkipping (consumer:Consumer<'T,'U>) = - match box consumer with - | :? ISkipping as skip -> skip.Skipping - | _ -> fun () -> false + interface IEnumerator with + member this.Current = box ((Upcast.enumerator this)).Current + member __.MoveNext () = + state <- SeqProcessNextStates.InProcess + moveNext () + member __.Reset () = noReset () - let init f (terminatingIdx:int) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let mutable idx = -1 - let isSkipping = makeIsSkipping consumer - let mutable maybeSkipping = true - while (outOfBand.HaltedIdx = 0) && (idx < terminatingIdx) do - if maybeSkipping then - maybeSkipping <- isSkipping () + interface IDisposable with + member __.Dispose() = + main.Dispose () + active.Dispose () - if not maybeSkipping then - consumer.ProcessNext (f (idx+1)) |> ignore + and AppendEnumerable<'T> (sources:list>) = + inherit EnumerableBase<'T>() - idx <- idx + 1 + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = + Upcast.enumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) - let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:SeqFactory<'T,'U>) executeOn = - let pipeline = OutOfBand() - let result = f (fun () -> (pipeline:>IOutOfBand).StopFurtherProcessing (current.PipeIdx+1)) - let consumer = current.Build pipeline result - try - executeOn pipeline consumer - let mutable stopTailCall = () - (Upcast.iCompletionChain consumer).ChainComplete (&stopTailCall, pipeline.HaltedIdx) - result - finally - let mutable stopTailCall = () - (Upcast.iCompletionChain consumer).ChainDispose (&stopTailCall) - - module Enumerable = - type Empty<'T>() = - let current () = failwith "library implementation error: Current should never be called" - interface IEnumerator<'T> with - member __.Current = current () - interface IEnumerator with - member __.Current = current () - member __.MoveNext () = false - member __.Reset (): unit = noReset () - interface IDisposable with - member __.Dispose () = () - - type EmptyEnumerators<'T>() = - static let element : IEnumerator<'T> = upcast (new Empty<'T> ()) - static member Element = element - - [] - type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ICompletionChain) = - interface IDisposable with - member __.Dispose() : unit = - let mutable stopTailCall = () - seqComponent.ChainDispose (&stopTailCall) + override this.Append source = + Upcast.enumerable (AppendEnumerable (source :: sources)) - interface IEnumerator with - member this.Current : obj = box ((Upcast.enumerator this)).Current - member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)" - member __.Reset () : unit = noReset () + interface ISeq<'T> with + member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable<'T,'V>(this, next)) - interface IEnumerator<'T> with - member __.Current = - if result.SeqState = SeqProcessNextStates.InProcess then result.Current - else - match result.SeqState with - | SeqProcessNextStates.NotStarted -> notStarted() - | SeqProcessNextStates.Finished -> alreadyFinished() - | _ -> failwith "library implementation error: all states should have been handled" + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) - and [] EnumerableBase<'T> () = - let derivedClassShouldImplement () = - failwith "library implementation error: derived class should implement (should be abstract)" + and ConcatEnumerable<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = + inherit EnumerableBase<'T>() - abstract member Append : (seq<'T>) -> IEnumerable<'T> + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = + Upcast.enumerator (new ConcatEnumerator<_,_> (sources)) - default this.Append source = Upcast.enumerable (AppendEnumerable [this; source]) + interface ISeq<'T> with + member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable<'T,'V>(this, next)) - interface IEnumerable with - member this.GetEnumerator () : IEnumerator = - let genericEnumerable = Upcast.enumerable this - let genericEnumerator = genericEnumerable.GetEnumerator () - Upcast.enumeratorNonGeneric genericEnumerator + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement () + let create enumerable current = + Upcast.seq (Enumerable(enumerable, current)) - interface ISeq<'T> with - member __.Compose _ = derivedClassShouldImplement () - member __.ForEach _ = derivedClassShouldImplement () + module EmptyEnumerable = + type Enumerable<'T> () = + inherit Enumerable.EnumerableBase<'T>() - and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit EnumeratorBase<'U>(result, seqComponent) + static let singleton = Enumerable<'T>() :> ISeq<'T> + static member Instance = singleton - let rec moveNext () = - if (result.HaltedIdx = 0) && source.MoveNext () then - if seqComponent.ProcessNext source.Current then - true - else - moveNext () - else - result.SeqState <- SeqProcessNextStates.Finished - let mutable stopTailCall = () - (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) - false + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>() - interface IEnumerator with - member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess - moveNext () + override this.Append source = + Upcast.enumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) - interface IDisposable with - member __.Dispose() = - try - source.Dispose () - finally - let mutable stopTailCall = () - (Upcast.iCompletionChain seqComponent).ChainDispose (&stopTailCall) + interface ISeq<'T> with + member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable.Enumerable<'T,'V>(this, next)) - and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqFactory<'T,'U>) = - inherit EnumerableBase<'U>() + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Build result (SetResult<'U> result), result)) - interface ISeq<'U> with - member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.enumerable enumerable) + module Array = + type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) - and ConcatEnumerator<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = - let mutable state = SeqProcessNextStates.NotStarted - let main = sources.GetEnumerator () + let mutable idx = 0 + let mutable array = Unchecked.defaultof<_> - let mutable active = EmptyEnumerators.Element + let mutable initMoveNext = Unchecked.defaultof<_> + do + initMoveNext <- + fun () -> + result.SeqState <- SeqProcessNextStates.InProcess + array <- delayedArray () + initMoveNext <- ignore - let rec moveNext () = - if active.MoveNext () then + let rec moveNext () = + if (result.HaltedIdx = 0) && idx < array.Length then + idx <- idx+1 + if seqComponent.ProcessNext array.[idx-1] then true - elif main.MoveNext () then - active.Dispose () - active <- main.Current.GetEnumerator () - moveNext () else - state <- SeqProcessNextStates.Finished - false - - interface IEnumerator<'T> with - member __.Current = - if state = SeqProcessNextStates.InProcess then active.Current - else - match state with - | SeqProcessNextStates.NotStarted -> notStarted() - | SeqProcessNextStates.Finished -> alreadyFinished() - | _ -> failwith "library implementation error: all states should have been handled" - - interface IEnumerator with - member this.Current = box ((Upcast.enumerator this)).Current - member __.MoveNext () = - state <- SeqProcessNextStates.InProcess moveNext () - member __.Reset () = noReset () + else + result.SeqState <- SeqProcessNextStates.Finished + let mutable stopTailCall = () + (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) + false - interface IDisposable with - member __.Dispose() = - main.Dispose () - active.Dispose () + interface IEnumerator with + member __.MoveNext () = + initMoveNext () + moveNext () - and AppendEnumerable<'T> (sources:list>) = - inherit EnumerableBase<'T>() + type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = - Upcast.enumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Upcast.enumerator (new Enumerator<'T,'U>(delayedArray, current.Build result (SetResult<'U> result), result)) - override this.Append source = - Upcast.enumerable (AppendEnumerable (source :: sources)) + interface ISeq<'U> with + member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) - interface ISeq<'T> with - member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = - Upcast.seq (Enumerable<'T,'V>(this, next)) + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.array (delayedArray ())) - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) + let createDelayed (delayedArray:unit->array<'T>) (current:SeqFactory<'T,'U>) = + Upcast.seq (Enumerable(delayedArray, current)) - and ConcatEnumerable<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = - inherit EnumerableBase<'T>() + let create (array:array<'T>) (current:SeqFactory<'T,'U>) = + createDelayed (fun () -> array) current - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = - Upcast.enumerator (new ConcatEnumerator<_,_> (sources)) + let createDelayedId (delayedArray:unit -> array<'T>) = + createDelayed delayedArray IdentityFactory.Instance - interface ISeq<'T> with - member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = - Upcast.seq (Enumerable<'T,'V>(this, next)) + let createId (array:array<'T>) = + create array IdentityFactory.Instance - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) + module List = + type Enumerator<'T,'U>(alist:list<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) - let create enumerable current = - Upcast.seq (Enumerable(enumerable, current)) + let mutable list = alist - module EmptyEnumerable = - type Enumerable<'T> () = - inherit Enumerable.EnumerableBase<'T>() + let rec moveNext current = + match result.HaltedIdx, current with + | 0, head::tail -> + if seqComponent.ProcessNext head then + list <- tail + true + else + moveNext tail + | _ -> + result.SeqState <- SeqProcessNextStates.Finished + let mutable stopTailCall = () + (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) + false - static let singleton = Enumerable<'T>() :> ISeq<'T> - static member Instance = singleton + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext list - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>() + type Enumerable<'T,'U>(alist:list<'T>, current:SeqFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() - override this.Append source = - Upcast.enumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Upcast.enumerator (new Enumerator<'T,'U>(alist, current.Build result (SetResult<'U> result), result)) - interface ISeq<'T> with - member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = - Upcast.seq (Enumerable.Enumerable<'T,'V>(this, next)) + interface ISeq<'U> with + member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.list alist) + let create alist current = + Upcast.seq (Enumerable(alist, current)) + module Unfold = + type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) - module Array = - type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + let mutable current = state - let mutable idx = 0 - let mutable array = Unchecked.defaultof<_> + let rec moveNext () = + match result.HaltedIdx, generator current with + | 0, Some (item, nextState) -> + current <- nextState + if seqComponent.ProcessNext item then + true + else + moveNext () + | _ -> false + + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext () + + type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Upcast.enumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Build result (SetResult<'U> result), result)) + + interface ISeq<'U> with + member this.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = + ForEach.execute f current (ForEach.unfold generator state) + + module Init = + // The original implementation of "init" delayed the calculation of Current, and so it was possible + // to do MoveNext without it's value being calculated. + // I can imagine only two scenerios where that is possibly sane, although a simple solution is readily + // at hand in both cases. The first is that of an expensive generator function, where you skip the + // first n elements. The simple solution would have just been to have a map ((+) n) as the first operation + // instead. The second case would be counting elements, but that is only of use if you're not filtering + // or mapping or doing anything else (as that would cause Current to be evaluated!) and + // so you already know what the count is!! Anyway, someone thought it was a good idea, so + // I have had to add an extra function that is used in Skip to determine if we are touching + // Current or not. + + let getTerminatingIdx (count:Nullable) = + // we are offset by 1 to allow for values going up to System.Int32.MaxValue + // System.Int32.MaxValue is an illegal value for the "infinite" sequence + if count.HasValue then + count.Value - 1 + else + System.Int32.MaxValue + + type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:Consumer<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + + let isSkipping = + ForEach.makeIsSkipping seqComponent + + let terminatingIdx = + getTerminatingIdx count + + let mutable maybeSkipping = true + let mutable idx = -1 + + let rec moveNext () = + if (result.HaltedIdx = 0) && idx < terminatingIdx then + idx <- idx + 1 - let mutable initMoveNext = Unchecked.defaultof<_> - do - initMoveNext <- - fun () -> - result.SeqState <- SeqProcessNextStates.InProcess - array <- delayedArray () - initMoveNext <- ignore + if maybeSkipping then + // Skip can only is only checked at the start of the sequence, so once + // triggered, we stay triggered. + maybeSkipping <- isSkipping () - let rec moveNext () = - if (result.HaltedIdx = 0) && idx < array.Length then - idx <- idx+1 - if seqComponent.ProcessNext array.[idx-1] then - true - else - moveNext () + if maybeSkipping then + moveNext () + elif seqComponent.ProcessNext (f idx) then + true else - result.SeqState <- SeqProcessNextStates.Finished - let mutable stopTailCall = () - (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) - false - - interface IEnumerator with - member __.MoveNext () = - initMoveNext () moveNext () + elif (result.HaltedIdx = 0) && idx = System.Int32.MaxValue then + raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) + else + result.SeqState <- SeqProcessNextStates.Finished + let mutable stopTailCall = () + (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) + false - type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqFactory<'T,'U>) = - inherit Enumerable.EnumerableBase<'U>() + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext () + + type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqFactory<'T,'U>) = + inherit Enumerable.EnumerableBase<'U>() + + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Upcast.enumerator (new Enumerator<'T,'U>(count, f, current.Build result (SetResult<'U> result), result)) + + interface ISeq<'U> with + member this.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + + member this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = + let terminatingIdx = getTerminatingIdx count + ForEach.execute createResult current (ForEach.init f terminatingIdx) + + let upto lastOption f = + match lastOption with + | Some b when b<0 -> failwith "library implementation error: upto can never be called with a negative value" + | _ -> + let unstarted = -1 // index value means unstarted (and no valid index) + let completed = -2 // index value means completed (and no valid index) + let unreachable = -3 // index is unreachable from 0,1,2,3,... + let finalIndex = match lastOption with + | Some b -> b // here b>=0, a valid end value. + | None -> unreachable // run "forever", well as far as Int32.MaxValue since indexing with a bounded type. + // The Current value for a valid index is "f i". + // Lazy<_> values are used as caches, to store either the result or an exception if thrown. + // These "Lazy<_>" caches are created only on the first call to current and forced immediately. + // The lazy creation of the cache nodes means enumerations that skip many Current values are not delayed by GC. + // For example, the full enumeration of Seq.initInfinite in the tests. + // state + let index = ref unstarted + // a Lazy node to cache the result/exception + let current = ref (Unchecked.defaultof<_>) + let setIndex i = index := i; current := (Unchecked.defaultof<_>) // cache node unprimed, initialised on demand. + let getCurrent() = + if !index = unstarted then notStarted() + if !index = completed then alreadyFinished() + match box !current with + | null -> current := Lazy<_>.Create(fun () -> f !index) + | _ -> () + // forced or re-forced immediately. + (!current).Force() + { new IEnumerator<'U> with + member x.Current = getCurrent() + interface IEnumerator with + member x.Current = box (getCurrent()) + member x.MoveNext() = + if !index = completed then + false + elif !index = unstarted then + setIndex 0 + true + else ( + if !index = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) + if !index = finalIndex then + false + else + setIndex (!index + 1) + true + ) + member self.Reset() = noReset() + interface System.IDisposable with + member x.Dispose() = () } + + type EnumerableDecider<'T>(count:Nullable, f:int->'T) = + inherit Enumerable.EnumerableBase<'T>() + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = + // we defer back to the original implementation as, as it's quite idiomatic in it's decision + // to calculate Current in a lazy fashion. I doubt anyone is really using this functionality + // in the way presented, but it's possible. + upto (if count.HasValue then Some (count.Value-1) else None) f + + interface ISeq<'T> with + member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable<'T,'V>(count, f, next)) + + member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = + ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (Upcast.enumerable this)) + + + [] + let toComposer (source:seq<'T>) : ISeq<'T> = + match source with + | :? ISeq<'T> as s -> s + | :? array<'T> as a -> Upcast.seq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) + | :? list<'T> as a -> Upcast.seq (List.Enumerable(a, IdentityFactory.Instance)) + | null -> nullArg "source" + | _ -> Upcast.seq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) + + + let inline foreach f (source:ISeq<_>) = source.ForEach f + let inline compose (factory:#SeqFactory<_,_>) (source:ISeq<'T>) = source.Compose factory + + [] + let inline average (source: ISeq< ^T>) : ^T + when ^T:(static member Zero : ^T) + and ^T:(static member (+) : ^T * ^T -> ^T) + and ^T:(static member DivideByInt : ^T * int -> ^T) = + source + |> foreach (fun _ -> + { new FolderWithOnComplete< ^T, Values< ^T, int>> (Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + override this.ProcessNext value = + this.Value._1 <- Checked.(+) this.Value._1 value + this.Value._2 <- this.Value._2 + 1 + Unchecked.defaultof<_> (* return value unsed in ForEach context *) + + override this.OnComplete _ = + if this.Value._2 = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) + |> fun total -> LanguagePrimitives.DivideByInt< ^T> total.Value._1 total.Value._2 + + + [] + let inline averageBy (f : 'T -> ^U) (source: ISeq< 'T >) : ^U + when ^U:(static member Zero : ^U) + and ^U:(static member (+) : ^U * ^U -> ^U) + and ^U:(static member DivideByInt : ^U * int -> ^U) = + source + |> foreach (fun _ -> + { new FolderWithOnComplete<'T,Values<'U, int>>(Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + override this.ProcessNext value = + this.Value._1 <- Checked.(+) this.Value._1 (f value) + this.Value._2 <- this.Value._2 + 1 + Unchecked.defaultof<_> (* return value unsed in ForEach context *) + + override this.OnComplete _ = + if this.Value._2 = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) + |> fun total -> LanguagePrimitives.DivideByInt< ^U> total.Value._1 total.Value._2 + + + [] + let empty<'T> = EmptyEnumerable.Enumerable<'T>.Instance + + + [] + let inline exactlyOne errorString (source : ISeq<'T>) : 'T = + source + |> foreach (fun halt -> + { new FolderWithOnComplete<'T, Values>(Values(true, Unchecked.defaultof<'T>, false)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + else + this.Value._3 <- true + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) + + override this.OnComplete _ = + if this.Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + elif this.Value._3 then + invalidArg "source" errorString }) + |> fun one -> one.Value._2 + + + [] + let inline fold<'T,'State> (f:'State->'T->'State) (seed:'State) (source:ISeq<'T>) : 'State = + source + |> foreach (fun _ -> + { new Folder<'T,'State>(seed) with + override this.ProcessNext value = + this.Value <- f this.Value value + Unchecked.defaultof<_> (* return value unsed in ForEach context *) + }) + |> fun folded -> folded.Value + + + [] + let inline fold2<'T1,'T2,'State> (folder:'State->'T1->'T2->'State) (state:'State) (source1: ISeq<'T1>) (source2: ISeq<'T2>) = + source1 + |> foreach (fun halt -> + { new FolderWithOnComplete<_,Values<'State,IEnumerator<'T2>>>(Values<_,_>(state,source2.GetEnumerator())) with + override self.ProcessNext value = + if self.Value._2.MoveNext() then + self.Value._1 <- folder self.Value._1 value self.Value._2.Current + else + halt() + Unchecked.defaultof<_> (* return value unsed in ForEach context *) - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U>(delayedArray, current.Build result (SetResult<'U> result), result)) + override self.OnComplete _ = + self.Value._2.Dispose() + }) + |> fun fold -> fold.Value._1 - interface ISeq<'U> with - member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.array (delayedArray ())) + [] + let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> = + Upcast.seq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) - let createDelayed (delayedArray:unit->array<'T>) (current:SeqFactory<'T,'U>) = - Upcast.seq (Enumerable(delayedArray, current)) - let create (array:array<'T>) (current:SeqFactory<'T,'U>) = - createDelayed (fun () -> array) current + [] + let initInfinite<'T> (f:int->'T) : ISeq<'T> = + Upcast.seq (new Init.EnumerableDecider<'T>(Nullable (), f)) - let createDelayedId (delayedArray:unit -> array<'T>) = - createDelayed delayedArray IdentityFactory.Instance - let createId (array:array<'T>) = - create array IdentityFactory.Instance + [] + let init<'T> (count:int) (f:int->'T) : ISeq<'T> = + if count < 0 then invalidArgInputMustBeNonNegative "count" count + elif count = 0 then empty else + Upcast.seq (new Init.EnumerableDecider<'T>(Nullable count, f)) - module List = - type Enumerator<'T,'U>(alist:list<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) - let mutable list = alist + [] + let iter f (source:ISeq<'T>) = + source + |> foreach (fun _ -> + { new Consumer<'T,'T> () with + override this.ProcessNext value = + f value + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> ignore - let rec moveNext current = - match result.HaltedIdx, current with - | 0, head::tail -> - if seqComponent.ProcessNext head then - list <- tail - true - else - moveNext tail - | _ -> - result.SeqState <- SeqProcessNextStates.Finished - let mutable stopTailCall = () - (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) - false - interface IEnumerator with - member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess - moveNext list + [] + let inline iter2 (f:'T->'U->unit) (source1:ISeq<'T>) (source2:ISeq<'U>) : unit = + source1 + |> foreach (fun halt -> + { new FolderWithOnComplete<'T,IEnumerator<'U>> (source2.GetEnumerator()) with + override self.ProcessNext value = + if self.Value.MoveNext() then + f value self.Value.Current + else + halt() + Unchecked.defaultof<_> (* return value unsed in ForEach context *) + + override self.OnComplete _ = + self.Value.Dispose() + }) + |> ignore + + + [] + let inline iteri2 (f:int->'T->'U->unit) (source1:ISeq<'T>) (source2:seq<'U>) : unit = + source1 + |> foreach (fun halt -> + { new FolderWithOnComplete<'T,Values>>(Values<_,_>(-1,source2.GetEnumerator())) with + override self.ProcessNext value = + if self.Value._2.MoveNext() then + f self.Value._1 value self.Value._2.Current + self.Value._1 <- self.Value._1 + 1 + Unchecked.defaultof<_> + else + halt() + Unchecked.defaultof<_> + + override self.OnComplete _ = + self.Value._2.Dispose() + + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> ignore + + + [] + let tryHead (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, Option<'T>> (None) with + override this.ProcessNext value = + this.Value <- Some value + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun head -> head.Value + + + [] + let iteri f (source:ISeq<'T>) = + source + |> foreach (fun _ -> + { new Folder<'T, int> (0) with + override this.ProcessNext value = + f this.Value value + this.Value <- this.Value + 1 + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> ignore + + [] + let inline except (itemsToExclude: seq<'T>) (source:ISeq<'T>) : ISeq<'T> when 'T:equality = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { new ConsumerChainedWithState<'T,'V,Lazy>> + (Upcast.iCompletionChain next,lazy(HashSet<'T>(itemsToExclude,HashIdentity.Structural<'T>))) with + override this.ProcessNext (input:'T) : bool = + if this.Value.Value.Add input then TailCall.avoid (next.ProcessNext input) + else false + }} + + + [] + let exists f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, bool> (false) with + override this.ProcessNext value = + if f value then + this.Value <- true + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun exists -> exists.Value + + + [] + let exists2 (predicate:'T->'U->bool) (source1: ISeq<'T>) (source2: ISeq<'U>) : bool = + source1 + |> foreach (fun halt -> + { new FolderWithOnComplete<'T,Values>>(Values<_,_>(false,source2.GetEnumerator())) with + override self.ProcessNext value = + if self.Value._2.MoveNext() then + if predicate value self.Value._2.Current then + self.Value._1 <- true + halt() + else + halt() + Unchecked.defaultof<_> (* return value unsed in ForEach context *) - type Enumerable<'T,'U>(alist:list<'T>, current:SeqFactory<'T,'U>) = - inherit Enumerable.EnumerableBase<'U>() + override self.OnComplete _ = + self.Value._2.Dispose() - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U>(alist, current.Build result (SetResult<'U> result), result)) + }) + |> fun exists -> exists.Value._1 - interface ISeq<'U> with - member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.list alist) + [] + let inline contains element (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, bool> (false) with + override this.ProcessNext value = + if element = value then + this.Value <- true + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun contains -> contains.Value + + + [] + let forall predicate (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, bool> (true) with + override this.ProcessNext value = + if not (predicate value) then + this.Value <- false + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun forall -> forall.Value + + + [] + let inline forall2 predicate (source1:ISeq<'T>) (source2:ISeq<'U>) : bool = + source1 + |> foreach (fun halt -> + { new FolderWithOnComplete<'T,Values>>(Values<_,_>(true,source2.GetEnumerator())) with + override self.ProcessNext value = + if self.Value._2.MoveNext() then + if not (predicate value self.Value._2.Current) then + self.Value._1 <- false + halt() + else + halt() + Unchecked.defaultof<_> (* return value unsed in ForEach context *) + + override self.OnComplete _ = + self.Value._2.Dispose() + }) + |> fun all -> all.Value._1 + + + [] + let inline filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with + member __.ProcessNext input = + if f input then TailCall.avoid (next.ProcessNext input) + else false } } + + + [] + let inline map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = + source |> compose { new SeqFactory<'T,'U>() with + member __.Create _ _ next = + upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with + member __.ProcessNext input = + TailCall.avoid (next.ProcessNext (f input)) } } + + + [] + let inline mapi f source = + source |> compose { new SeqFactory<'T,'U>() with + member __.Create _ _ next = + upcast { new ConsumerChainedWithState<'T,'V,int>(Upcast.iCompletionChain next, -1) with + override this.ProcessNext (input:'T) : bool = + this.Value <- this.Value + 1 + TailCall.avoid (next.ProcessNext (f this.Value input)) } } + + + [] + let inline map2<'First,'Second,'U> (map:'First->'Second->'U) (source1:ISeq<'First>) (source2:ISeq<'Second>) : ISeq<'U> = + source1 |> compose { new SeqFactory<'First,'U>() with + member __.Create<'V> outOfBand pipeIdx next = + upcast { new ConsumerChainedWithStateAndCleanup<'First,'V, IEnumerator<'Second>>(Upcast.iCompletionChain next, (source2.GetEnumerator ())) with + member self.ProcessNext input = + if self.Value.MoveNext () then + TailCall.avoid (next.ProcessNext (map input self.Value.Current)) + else + outOfBand.StopFurtherProcessing pipeIdx + false + + override self.OnDispose () = () + override self.OnComplete _ = + self.Value.Dispose () } } + + + [] + let inline mapi2<'First,'Second,'U> (map:int -> 'First->'Second->'U) (source1:ISeq<'First>) (source2:ISeq<'Second>) : ISeq<'U> = + source1 |> compose { new SeqFactory<'First,'U>() with + member __.Create<'V> outOfBand pipeIdx next = + upcast { new ConsumerChainedWithStateAndCleanup<'First,'V, Values>> + (Upcast.iCompletionChain next, Values<_,_>(-1, source2.GetEnumerator ())) with + member self.ProcessNext input = + if self.Value._2.MoveNext () then + self.Value._1 <- self.Value._1 + 1 + TailCall.avoid (next.ProcessNext (map self.Value._1 input self.Value._2.Current)) + else + outOfBand.StopFurtherProcessing pipeIdx + false + + override self.OnDispose () = () + override self.OnComplete _ = + self.Value._2.Dispose () } } + + + [] + let inline map3<'First,'Second,'Third,'U> + (map:'First->'Second->'Third->'U) (source1:ISeq<'First>) (source2:ISeq<'Second>) (source3:ISeq<'Third>) : ISeq<'U> = + source1 |> compose { new SeqFactory<'First,'U>() with + member __.Create<'V> outOfBand pipeIdx next = + upcast { new ConsumerChainedWithStateAndCleanup<'First,'V, Values,IEnumerator<'Third>>> + (Upcast.iCompletionChain next, Values<_,_>(source2.GetEnumerator(),source3.GetEnumerator())) with + member self.ProcessNext input = + if self.Value._1.MoveNext() && self.Value._2.MoveNext () then + TailCall.avoid (next.ProcessNext (map input self.Value._1 .Current self.Value._2.Current)) + else + outOfBand.StopFurtherProcessing pipeIdx + false + + override self.OnDispose () = () + override self.OnComplete _ = + self.Value._1.Dispose () + self.Value._2.Dispose () } } + + + [] + let inline compareWith (f:'T -> 'T -> int) (source1 :ISeq<'T>) (source2:ISeq<'T>) : int = + source1 + |> foreach (fun halt -> + { new FolderWithOnComplete<'T,Values>>(Values<_,_>(0,source2.GetEnumerator())) with + override self.ProcessNext value = + if not (self.Value._2.MoveNext()) then + self.Value._1 <- 1 + halt () + else + let c = f value self.Value._2.Current + if c <> 0 then + self.Value._1 <- c + halt () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) + + override self.OnComplete _ = + if self.Value._1 = 0 && self.Value._2.MoveNext() then + self.Value._1 <- -1 + self.Value._2.Dispose() + }) + |> fun compare -> compare.Value._1 + + [] + let inline choose (f:'T->option<'U>) (source:ISeq<'T>) : ISeq<'U> = + source |> compose { new SeqFactory<'T,'U>() with + member __.Create _ _ next = + upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with + member __.ProcessNext input = + match f input with + | Some value -> TailCall.avoid (next.ProcessNext value) + | None -> false } } + + + [] + let inline distinct (source:ISeq<'T>) : ISeq<'T> when 'T:equality = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { new ConsumerChainedWithState<'T,'V,HashSet<'T>> + (Upcast.iCompletionChain next,(HashSet<'T>(HashIdentity.Structural<'T>))) with + override this.ProcessNext (input:'T) : bool = + if this.Value.Add input then TailCall.avoid (next.ProcessNext input) + else false } } + + + [] + let inline distinctBy (keyf:'T->'Key) (source:ISeq<'T>) :ISeq<'T> when 'Key:equality = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { new ConsumerChainedWithState<'T,'V,HashSet<'Key>> + (Upcast.iCompletionChain next,(HashSet<'Key>(HashIdentity.Structural<'Key>))) with + override this.ProcessNext (input:'T) : bool = + if this.Value.Add (keyf input) then TailCall.avoid (next.ProcessNext input) + else false } } + + + [] + let inline max (source: ISeq<'T>) : 'T when 'T:comparison = + source + |> foreach (fun _ -> + { new FolderWithOnComplete<'T,Values>(Values<_,_>(true, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + elif value > this.Value._2 then + this.Value._2 <- value + Unchecked.defaultof<_> (* return value unsed in ForEach context *) + + override this.OnComplete _ = + if this.Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun max -> max.Value._2 + + + [] + let inline maxBy (f :'T -> 'U) (source: ISeq<'T>) : 'T when 'U:comparison = + source + |> foreach (fun _ -> + { new FolderWithOnComplete<'T,Values>(Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + match this.Value._1, f value with + | true, valueU -> + this.Value._1 <- false + this.Value._2 <- valueU + this.Value._3 <- value + | false, valueU when valueU > this.Value._2 -> + this.Value._2 <- valueU + this.Value._3 <- value + | _ -> () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) + + override this.OnComplete _ = + if this.Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun min -> min.Value._3 + + + [] + let inline min (source: ISeq< 'T>) : 'T when 'T:comparison = + source + |> foreach (fun _ -> + { new FolderWithOnComplete<'T,Values>(Values<_,_>(true, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + elif value < this.Value._2 then + this.Value._2 <- value + Unchecked.defaultof<_> (* return value unsed in ForEach context *) + + override this.OnComplete _ = + if this.Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun min -> min.Value._2 + + + [] + let inline minBy (f : 'T -> 'U) (source: ISeq<'T>) : 'T = + source + |> foreach (fun _ -> + { new FolderWithOnComplete< 'T,Values>(Values<_,_,_>(true,Unchecked.defaultof< 'U>,Unchecked.defaultof< 'T>)) with + override this.ProcessNext value = + match this.Value._1, f value with + | true, valueU -> + this.Value._1 <- false + this.Value._2 <- valueU + this.Value._3 <- value + | false, valueU when valueU < this.Value._2 -> + this.Value._2 <- valueU + this.Value._3 <- value + | _ -> () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) + + override this.OnComplete _ = + if this.Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun min -> min.Value._3 + + + [] + let inline pairwise (source:ISeq<'T>) : ISeq<'T * 'T> = + source |> compose { new SeqFactory<'T,'T * 'T>() with + member __.Create _ _ next = + upcast { new ConsumerChainedWithState<'T,'U,Values> + ( Upcast.iCompletionChain next + , Values + ((* isFirst = _1*) true + ,(* lastValue = _2*) Unchecked.defaultof<'T> + ) + ) with + override self.ProcessNext (input:'T) : bool = + if (*isFirst*) self.Value._1 then + self.Value._2 (*lastValue*)<- input + self.Value._1 (*isFirst*)<- false + false + else + let currentPair = self.Value._2, input + self.Value._2 (*lastValue*)<- input + TailCall.avoid (next.ProcessNext currentPair) + }} + + + [] + let inline reduce (f:'T->'T->'T) (source : ISeq<'T>) : 'T = + source + |> foreach (fun _ -> + { new FolderWithOnComplete<'T, Values>(Values<_,_>(true, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + else + this.Value._2 <- f this.Value._2 value + Unchecked.defaultof<_> (* return value unsed in ForEach context *) - let create alist current = - Upcast.seq (Enumerable(alist, current)) + override this.OnComplete _ = + if this.Value._1 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + }) + |> fun reduced -> reduced.Value._2 - module Unfold = - type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) - let mutable current = state + [] + let inline scan (folder:'State->'T->'State) (initialState: 'State) (source:ISeq<'T>) :ISeq<'State> = + source |> compose { new SeqFactory<'T,'State>() with + member __.Create _ _ next = + upcast { new ConsumerChainedWithState<'T,'V,'State>(Upcast.iCompletionChain next, initialState) with + override this.ProcessNext (input:'T) : bool = + this.Value <- folder this.Value input + TailCall.avoid (next.ProcessNext this.Value) } } - let rec moveNext () = - match result.HaltedIdx, generator current with - | 0, Some (item, nextState) -> - current <- nextState - if seqComponent.ProcessNext item then - true - else - moveNext () - | _ -> false - interface IEnumerator with - member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess - moveNext () + [] + let inline skip (errorString:string) (skipCount:int) (source:ISeq<'T>) : ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { + new ConsumerChainedWithStateAndCleanup<'T,'U,int>(Upcast.iCompletionChain next,(*count*)0) with - type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqFactory<'T,'U>) = - inherit Enumerable.EnumerableBase<'U>() - - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Build result (SetResult<'U> result), result)) - - interface ISeq<'U> with - member this.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.unfold generator state) - - module Init = - // The original implementation of "init" delayed the calculation of Current, and so it was possible - // to do MoveNext without it's value being calculated. - // I can imagine only two scenerios where that is possibly sane, although a simple solution is readily - // at hand in both cases. The first is that of an expensive generator function, where you skip the - // first n elements. The simple solution would have just been to have a map ((+) n) as the first operation - // instead. The second case would be counting elements, but that is only of use if you're not filtering - // or mapping or doing anything else (as that would cause Current to be evaluated!) and - // so you already know what the count is!! Anyway, someone thought it was a good idea, so - // I have had to add an extra function that is used in Skip to determine if we are touching - // Current or not. - - let getTerminatingIdx (count:Nullable) = - // we are offset by 1 to allow for values going up to System.Int32.MaxValue - // System.Int32.MaxValue is an illegal value for the "infinite" sequence - if count.HasValue then - count.Value - 1 - else - System.Int32.MaxValue + override self.ProcessNext (input:'T) : bool = + if (*count*) self.Value < skipCount then + self.Value <- self.Value + 1 + false + else + TailCall.avoid (next.ProcessNext input) - type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + override self.OnDispose () = () + override self.OnComplete _ = + if (*count*) self.Value < skipCount then + let x = skipCount - self.Value + invalidOpFmt "{0}\ntried to skip {1} {2} past the end of the seq" + [|errorString; x; (if x=1 then "element" else "elements")|] + + interface ISkipping with + member self.Skipping () = + let self = self :?> ConsumerChainedWithState<'T,'U,int> + if (*count*) self.Value < skipCount then + self.Value <- self.Value + 1 + true + else + false + }} - let isSkipping = - ForEach.makeIsSkipping seqComponent - let terminatingIdx = - getTerminatingIdx count + [] + let inline skipWhile (predicate:'T->bool) (source:ISeq<'T>) : ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { new ConsumerChainedWithState<'T,'V,bool>(Upcast.iCompletionChain next,true) with + override self.ProcessNext (input:'T) : bool = + if self.Value (*skip*) then + self.Value <- predicate input + if self.Value (*skip*) then + false + else + TailCall.avoid (next.ProcessNext input) + else + TailCall.avoid (next.ProcessNext input) }} + + + [] + let inline sum (source:ISeq< ^T>) : ^T + when ^T:(static member Zero : ^T) + and ^T:(static member (+) : ^T * ^T -> ^T) = + source + |> foreach (fun _ -> + { new Folder< ^T,^T> (LanguagePrimitives.GenericZero) with + override this.ProcessNext value = + this.Value <- Checked.(+) this.Value value + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun sum -> sum.Value + + + [] + let inline sumBy (f : 'T -> ^U) (source: ISeq<'T>) : ^U + when ^U:(static member Zero : ^U) + and ^U:(static member (+) : ^U * ^U -> ^U) = + source + |> foreach (fun _ -> + { new Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + override this.ProcessNext value = + this.Value <- Checked.(+) this.Value (f value) + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun sum -> sum.Value + + + [] + let inline take (errorString:string) (takeCount:int) (source:ISeq<'T>) : ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create outOfBand pipelineIdx next = + upcast { + new ConsumerChainedWithStateAndCleanup<'T,'U,int>(Upcast.iCompletionChain next,(*count*)0) with + override self.ProcessNext (input:'T) : bool = + if (*count*) self.Value < takeCount then + self.Value <- self.Value + 1 + if self.Value = takeCount then + outOfBand.StopFurtherProcessing pipelineIdx + TailCall.avoid (next.ProcessNext input) + else + outOfBand.StopFurtherProcessing pipelineIdx + false - let mutable maybeSkipping = true - let mutable idx = -1 + override this.OnDispose () = () + override this.OnComplete terminatingIdx = + if terminatingIdx < pipelineIdx && this.Value < takeCount then + let x = takeCount - this.Value + invalidOpFmt "tried to take {0} {1} past the end of the seq" + [|errorString; x; (if x=1 then "element" else "elements")|] + }} + + + [] + let inline takeWhile (predicate:'T->bool) (source:ISeq<'T>) : ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create outOfBand pipeIdx next = + upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with + override __.ProcessNext (input:'T) : bool = + if predicate input then + TailCall.avoid (next.ProcessNext input) + else + outOfBand.StopFurtherProcessing pipeIdx + false + }} + + + [] + let inline tail errorString (source:ISeq<'T>) :ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create _ _ next = + upcast { new ConsumerChainedWithStateAndCleanup<'T,'V,bool>(Upcast.iCompletionChain next,(*first*) true) with + override self.ProcessNext (input:'T) : bool = + if (*first*) self.Value then + self.Value <- false + false + else + TailCall.avoid (next.ProcessNext input) - let rec moveNext () = - if (result.HaltedIdx = 0) && idx < terminatingIdx then - idx <- idx + 1 + override self.OnDispose () = () + override self.OnComplete _ = + if (*first*) self.Value then + invalidArg "source" errorString + }} - if maybeSkipping then - // Skip can only is only checked at the start of the sequence, so once - // triggered, we stay triggered. - maybeSkipping <- isSkipping () - if maybeSkipping then - moveNext () - elif seqComponent.ProcessNext (f idx) then - true - else - moveNext () - elif (result.HaltedIdx = 0) && idx = System.Int32.MaxValue then - raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) - else - result.SeqState <- SeqProcessNextStates.Finished - let mutable stopTailCall = () - (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) - false + [] + let inline truncate (truncateCount:int) (source:ISeq<'T>) : ISeq<'T> = + source |> compose { new SeqFactory<'T,'T>() with + member __.Create outOfBand pipeIdx next = + upcast { + new ConsumerChainedWithState<'T,'U,int>(Upcast.iCompletionChain next,(*count*)0) with + override self.ProcessNext (input:'T) : bool = + if (*count*) self.Value < truncateCount then + self.Value <- self.Value + 1 + if self.Value = truncateCount then + outOfBand.StopFurtherProcessing pipeIdx + TailCall.avoid (next.ProcessNext input) + else + outOfBand.StopFurtherProcessing pipeIdx + false + }} - interface IEnumerator with - member __.MoveNext () = - result.SeqState <- SeqProcessNextStates.InProcess - moveNext () - type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqFactory<'T,'U>) = - inherit Enumerable.EnumerableBase<'U>() + [] + let inline indexed source = + mapi (fun i x -> i,x) source - interface IEnumerable<'U> with - member this.GetEnumerator () : IEnumerator<'U> = - let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U>(count, f, current.Build result (SetResult<'U> result), result)) - interface ISeq<'U> with - member this.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + [] + let tryItem (errorString:string) index (source:ISeq<'T>) = + if index < 0 then None else + source |> skip errorString index |> tryHead - member this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = - let terminatingIdx = getTerminatingIdx count - ForEach.execute createResult current (ForEach.init f terminatingIdx) - let upto lastOption f = - match lastOption with - | Some b when b<0 -> failwith "library implementation error: upto can never be called with a negative value" - | _ -> - let unstarted = -1 // index value means unstarted (and no valid index) - let completed = -2 // index value means completed (and no valid index) - let unreachable = -3 // index is unreachable from 0,1,2,3,... - let finalIndex = match lastOption with - | Some b -> b // here b>=0, a valid end value. - | None -> unreachable // run "forever", well as far as Int32.MaxValue since indexing with a bounded type. - // The Current value for a valid index is "f i". - // Lazy<_> values are used as caches, to store either the result or an exception if thrown. - // These "Lazy<_>" caches are created only on the first call to current and forced immediately. - // The lazy creation of the cache nodes means enumerations that skip many Current values are not delayed by GC. - // For example, the full enumeration of Seq.initInfinite in the tests. - // state - let index = ref unstarted - // a Lazy node to cache the result/exception - let current = ref (Unchecked.defaultof<_>) - let setIndex i = index := i; current := (Unchecked.defaultof<_>) // cache node unprimed, initialised on demand. - let getCurrent() = - if !index = unstarted then notStarted() - if !index = completed then alreadyFinished() - match box !current with - | null -> current := Lazy<_>.Create(fun () -> f !index) - | _ -> () - // forced or re-forced immediately. - (!current).Force() - { new IEnumerator<'U> with - member x.Current = getCurrent() - interface IEnumerator with - member x.Current = box (getCurrent()) - member x.MoveNext() = - if !index = completed then - false - elif !index = unstarted then - setIndex 0 - true - else ( - if !index = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) - if !index = finalIndex then - false - else - setIndex (!index + 1) - true - ) - member self.Reset() = noReset() - interface System.IDisposable with - member x.Dispose() = () } - - type EnumerableDecider<'T>(count:Nullable, f:int->'T) = - inherit Enumerable.EnumerableBase<'T>() - - interface IEnumerable<'T> with - member this.GetEnumerator () : IEnumerator<'T> = - // we defer back to the original implementation as, as it's quite idiomatic in it's decision - // to calculate Current in a lazy fashion. I doubt anyone is really using this functionality - // in the way presented, but it's possible. - upto (if count.HasValue then Some (count.Value-1) else None) f - - interface ISeq<'T> with - member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = - Upcast.seq (Enumerable<'T,'V>(count, f, next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (Upcast.enumerable this)) - - [] - let toComposer (source:seq<'T>) : ISeq<'T> = - match source with - | :? ISeq<'T> as s -> s - | :? array<'T> as a -> Upcast.seq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) - | :? list<'T> as a -> Upcast.seq (List.Enumerable(a, IdentityFactory.Instance)) - | null -> nullArg "source" - | _ -> Upcast.seq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) - - let inline foreach f (source:ISeq<_>) = - source.ForEach f - - let inline compose (factory:#SeqFactory<_,_>) (source:ISeq<'T>) = - source.Compose factory - - [] - let empty<'T> = EmptyEnumerable.Enumerable<'T>.Instance - - [] - let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> = - Upcast.seq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) - - [] - let initInfinite<'T> (f:int->'T) : ISeq<'T> = - Upcast.seq (new Init.EnumerableDecider<'T>(Nullable (), f)) - - [] - let init<'T> (count:int) (f:int->'T) : ISeq<'T> = - if count < 0 then invalidArgInputMustBeNonNegative "count" count - elif count = 0 then empty else - Upcast.seq (new Init.EnumerableDecider<'T>(Nullable count, f)) - - [] - let iter f (source:ISeq<'T>) = - source - |> foreach (fun _ -> - { new Consumer<'T,'T> () with - override this.ProcessNext value = - f value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> ignore - - [] - let tryHead (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, Option<'T>> (None) with - override this.ProcessNext value = + [] + let tryPick f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, Option<'U>> (None) with + override this.ProcessNext value = + match f value with + | (Some _) as some -> + this.Value <- some + halt () + | None -> () + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun pick -> pick.Value + + + [] + let tryFind f (source:ISeq<'T>) = + source + |> foreach (fun halt -> + { new Folder<'T, Option<'T>> (None) with + override this.ProcessNext value = + if f value then this.Value <- Some value halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun head -> head.Value - - - - [] - let iteri f (source:ISeq<'T>) = - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f - - source - |> foreach (fun _ -> - { new Folder<'T, int> (0) with - override this.ProcessNext value = - f.Invoke(this.Value, value) - this.Value <- this.Value + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> ignore - - [] - let inline except (itemsToExclude: seq<'T>) (source:ISeq<'T>) : ISeq<'T> when 'T:equality = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,Lazy>> - (Upcast.iCompletionChain next,lazy(HashSet<'T>(itemsToExclude,HashIdentity.Structural<'T>))) with - override this.ProcessNext (input:'T) : bool = - if this.Value.Value.Add input then TailCall.avoid (next.ProcessNext input) - else false - }} - - [] - let exists f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, bool> (false) with - override this.ProcessNext value = - if f value then - this.Value <- true - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun exists -> exists.Value - - [] - let inline contains element (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, bool> (false) with - override this.ProcessNext value = - if element = value then - this.Value <- true - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun contains -> contains.Value - - [] - let forall f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, bool> (true) with - override this.ProcessNext value = - if not (f value) then - this.Value <- false - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun forall -> forall.Value - - [] - let inline filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with - member __.ProcessNext input = - if f input then TailCall.avoid (next.ProcessNext input) - else false } } - - [] - let inline map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = - source |> compose { new SeqFactory<'T,'U>() with - member __.Create _ _ next = - upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with - member __.ProcessNext input = - TailCall.avoid (next.ProcessNext (f input)) } } - - [] - let inline mapi f source = - source |> compose { new SeqFactory<'T,'U>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,int>(Upcast.iCompletionChain next, -1) with - override this.ProcessNext (input:'T) : bool = - this.Value <- this.Value + 1 - TailCall.avoid (next.ProcessNext (f this.Value input)) } } - - let mapi_adapt (f:OptimizedClosures.FSharpFunc<_,_,_>) source = - source |> compose { new SeqFactory<'T,'U>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,int>(Upcast.iCompletionChain next, -1) with - override this.ProcessNext (input:'T) : bool = - this.Value <- this.Value + 1 - TailCall.avoid (next.ProcessNext (f.Invoke (this.Value, input))) } } - - [] - let inline choose (f:'T->option<'U>) (source:ISeq<'T>) : ISeq<'U> = - source |> compose { new SeqFactory<'T,'U>() with - member __.Create _ _ next = - upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with - member __.ProcessNext input = - match f input with - | Some value -> TailCall.avoid (next.ProcessNext value) - | None -> false } } - - [] - let inline distinct (source:ISeq<'T>) : ISeq<'T> when 'T:equality = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,HashSet<'T>> - (Upcast.iCompletionChain next,(HashSet<'T>(HashIdentity.Structural<'T>))) with - override this.ProcessNext (input:'T) : bool = - if this.Value.Add input then TailCall.avoid (next.ProcessNext input) - else false } } - - [] - let inline distinctBy (keyf:'T->'Key) (source:ISeq<'T>) :ISeq<'T> when 'Key:equality = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,HashSet<'Key>> - (Upcast.iCompletionChain next,(HashSet<'Key>(HashIdentity.Structural<'Key>))) with - override this.ProcessNext (input:'T) : bool = - if this.Value.Add (keyf input) then TailCall.avoid (next.ProcessNext input) - else false } } - - [] - let inline pairwise (source:ISeq<'T>) : ISeq<'T * 'T> = - source |> compose { new SeqFactory<'T,'T * 'T>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'U,Values> + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun find -> find.Value + + + [] + let inline tryFindIndex (predicate:'T->bool) (source:ISeq<'T>) : int option = + source + |> foreach (fun halt -> + { new Folder<'T, Values, int>>(Values<_,_>(None, 0)) with + override this.ProcessNext value = + if predicate value then + this.Value._1 <- Some(this.Value._2) + halt () + else + this.Value._2 <- this.Value._2 + 1 + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun tried -> tried.Value._1 + + [] + let inline tryLast (source :ISeq<'T>) : 'T option = + source + |> foreach (fun _ -> + { new Folder<'T, Values>(Values(true, Unchecked.defaultof<'T>)) with + override this.ProcessNext value = + if this.Value._1 then + this.Value._1 <- false + this.Value._2 <- value + Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) + |> fun tried -> + if tried.Value._1 then + None + else + Some tried.Value._2 + + + [] + let inline windowed (windowSize:int) (source:ISeq<'T>) : ISeq<'T[]> = + source |> compose { new SeqFactory<'T,'T[]>() with + member __.Create outOfBand pipeIdx next = + upcast { + new ConsumerChainedWithState<'T,'U,Values<'T[],int,int>> ( Upcast.iCompletionChain next - , Values - ((* isFirst = _1*) true - ,(* lastValue = _2*) Unchecked.defaultof<'T> + , Values<'T[],int,int> + ((*circularBuffer = _1 *) Array.zeroCreateUnchecked windowSize + ,(* idx = _2 *) 0 + ,(* priming = _3 *) windowSize-1 ) ) with - override self.ProcessNext (input:'T) : bool = - if (*isFirst*) self.Value._1 then - self.Value._2 (*lastValue*)<- input - self.Value._1 (*isFirst*)<- false - false - else - let currentPair = self.Value._2, input - self.Value._2 (*lastValue*)<- input - TailCall.avoid (next.ProcessNext currentPair) - }} - - [] - let inline scan (folder:'State->'T->'State) (initialState: 'State) (source:ISeq<'T>) :ISeq<'State> = - source |> compose { new SeqFactory<'T,'State>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,'State>(Upcast.iCompletionChain next, initialState) with - override this.ProcessNext (input:'T) : bool = - this.Value <- folder this.Value input - TailCall.avoid (next.ProcessNext this.Value) } } - - - let scan_adapt (folder:OptimizedClosures.FSharpFunc<'State,'T,'State>) (initialState: 'State) (source:ISeq<'T>) :ISeq<'State> = - source |> compose { new SeqFactory<'T,'State>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,'State>(Upcast.iCompletionChain next, initialState) with - override this.ProcessNext (input:'T) : bool = - this.Value <- folder.Invoke(this.Value,input) - TailCall.avoid (next.ProcessNext this.Value) } } - - [] - let inline skip (skipCount:int) (source:ISeq<'T>) : ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { - new ConsumerChainedWithStateAndCleanup<'T,'U,int>(Upcast.iCompletionChain next,(*count*)0) with - - override self.ProcessNext (input:'T) : bool = - if (*count*) self.Value < skipCount then - self.Value <- self.Value + 1 - false - else - TailCall.avoid (next.ProcessNext input) - - override self.OnDispose () = () - override self.OnComplete _ = - if (*count*) self.Value < skipCount then - let x = skipCount - self.Value - invalidOpFmt "{0}\ntried to skip {1} {2} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - - interface ISkipping with - member self.Skipping () = - let self = self :?> ConsumerChainedWithState<'T,'U,int> - if (*count*) self.Value < skipCount then - self.Value <- self.Value + 1 - true - else - false - }} - - [] - let inline skipWhile (predicate:'T->bool) (source:ISeq<'T>) : ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,bool>(Upcast.iCompletionChain next,true) with override self.ProcessNext (input:'T) : bool = - if self.Value (*skip*) then - self.Value <- predicate input - if self.Value (*skip*) then - false - else - TailCall.avoid (next.ProcessNext input) - else - TailCall.avoid (next.ProcessNext input) }} - - [] - let inline take (takeCount:int) (source:ISeq<'T>) : ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create outOfBand pipelineIdx next = - upcast { - new ConsumerChainedWithStateAndCleanup<'T,'U,int>(Upcast.iCompletionChain next,(*count*)0) with - override self.ProcessNext (input:'T) : bool = - if (*count*) self.Value < takeCount then - self.Value <- self.Value + 1 - if self.Value = takeCount then - outOfBand.StopFurtherProcessing pipelineIdx - TailCall.avoid (next.ProcessNext input) - else - outOfBand.StopFurtherProcessing pipelineIdx - false + self.Value._1.[(* idx *)self.Value._2] <- input - override this.OnDispose () = () - override this.OnComplete terminatingIdx = - if terminatingIdx < pipelineIdx && this.Value < takeCount then - let x = takeCount - this.Value - invalidOpFmt "tried to take {0} {1} past the end of the seq" - [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] - }} - - [] - let inline takeWhile (predicate:'T->bool) (source:ISeq<'T>) : ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create outOfBand pipeIdx next = - upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with - override __.ProcessNext (input:'T) : bool = - if predicate input then - TailCall.avoid (next.ProcessNext input) - else - outOfBand.StopFurtherProcessing pipeIdx - false - }} + self.Value._2 <- (* idx *)self.Value._2 + 1 + if (* idx *) self.Value._2 = windowSize then + self.Value._2 <- 0 - [] - let inline tail (source:ISeq<'T>) :ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithStateAndCleanup<'T,'V,bool>(Upcast.iCompletionChain next,(*first*) true) with - override self.ProcessNext (input:'T) : bool = - if (*first*) self.Value then - self.Value <- false + if (* priming *) self.Value._3 > 0 then + self.Value._3 <- self.Value._3 - 1 false else - TailCall.avoid (next.ProcessNext input) - - override self.OnDispose () = () - override self.OnComplete _ = - if (*first*) self.Value then - invalidArg "source" (SR.GetString(SR.notEnoughElements)) - }} - - [] - let inline truncate (truncateCount:int) (source:ISeq<'T>) : ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create outOfBand pipeIdx next = - upcast { - new ConsumerChainedWithState<'T,'U,int>(Upcast.iCompletionChain next,(*count*)0) with - override self.ProcessNext (input:'T) : bool = - if (*count*) self.Value < truncateCount then - self.Value <- self.Value + 1 - if self.Value = truncateCount then - outOfBand.StopFurtherProcessing pipeIdx - TailCall.avoid (next.ProcessNext input) + if windowSize < 32 then + let window :'T [] = Array.init windowSize (fun i -> self.Value._1.[((* idx *)self.Value._2+i) % windowSize]: 'T) + TailCall.avoid (next.ProcessNext window) else - outOfBand.StopFurtherProcessing pipeIdx - false - }} - - [] - let inline indexed source = - mapi (fun i x -> i,x) source - - [] - let tryItem index (source:ISeq<'T>) = - if index < 0 then None else - source |> skip index |> tryHead - - [] - let tryPick f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, Option<'U>> (None) with - override this.ProcessNext value = - match f value with - | (Some _) as some -> - this.Value <- some - halt () - | None -> () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun pick -> pick.Value - - [] - let tryFind f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, Option<'T>> (None) with - override this.ProcessNext value = - if f value then - this.Value <- Some value - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun find -> find.Value - - [] - let inline windowed (windowSize:int) (source:ISeq<'T>) : ISeq<'T[]> = - source |> compose { new SeqFactory<'T,'T[]>() with - member __.Create outOfBand pipeIdx next = - upcast { - new ConsumerChainedWithState<'T,'U,Values<'T[],int,int>> - ( Upcast.iCompletionChain next - , Values<'T[],int,int> - ((*circularBuffer = _1 *) Array.zeroCreateUnchecked windowSize - ,(* idx = _2 *) 0 - ,(* priming = _3 *) windowSize-1 - ) - ) with - override self.ProcessNext (input:'T) : bool = - self.Value._1.[(* idx *)self.Value._2] <- input - - self.Value._2 <- (* idx *)self.Value._2 + 1 - if (* idx *) self.Value._2 = windowSize then - self.Value._2 <- 0 - - if (* priming *) self.Value._3 > 0 then - self.Value._3 <- self.Value._3 - 1 - false - else - if windowSize < 32 then - let window :'T [] = Array.init windowSize (fun i -> self.Value._1.[((* idx *)self.Value._2+i) % windowSize]: 'T) - TailCall.avoid (next.ProcessNext window) - else - let window = Array.zeroCreateUnchecked windowSize - Array.Copy((*circularBuffer*)self.Value._1, (* idx *)self.Value._2, window, 0, windowSize - (* idx *)self.Value._2) - Array.Copy((*circularBuffer*)self.Value._1, 0, window, windowSize - (* idx *)self.Value._2, (* idx *)self.Value._2) - TailCall.avoid (next.ProcessNext window) - - }} + let window = Array.zeroCreateUnchecked windowSize + Array.Copy((*circularBuffer*)self.Value._1, (* idx *)self.Value._2, window, 0, windowSize - (* idx *)self.Value._2) + Array.Copy((*circularBuffer*)self.Value._1, 0, window, windowSize - (* idx *)self.Value._2, (* idx *)self.Value._2) + TailCall.avoid (next.ProcessNext window) + + }} diff --git a/src/fsharp/FSharp.Core/seqcomposer.fsi b/src/fsharp/FSharp.Core/seqcomposer.fsi index 9b66a5e49b1..c4f352f0988 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fsi +++ b/src/fsharp/FSharp.Core/seqcomposer.fsi @@ -78,7 +78,7 @@ namespace Microsoft.FSharp.Collections inherit ConsumerChainedWithState<'T,'U,NoValue> new : next:ICompletionChain -> ConsumerChained<'T,'U> - [] + [] type ConsumerChainedWithStateAndCleanup<'T,'U,'Value> = inherit ConsumerChainedWithState<'T,'U,'Value> interface ICompletionChain @@ -124,449 +124,449 @@ namespace Microsoft.FSharp.Collections open Core - module internal Seq = - type ComposedFactory<'T,'U,'V> = - class - inherit SeqFactory<'T,'V> - private new : first: SeqFactory<'T,'U> * - second: SeqFactory<'U,'V> * - secondPipeIdx: PipeIdx -> - ComposedFactory<'T,'U,'V> - static member - Combine : first: SeqFactory<'T,'U> -> - second: SeqFactory<'U,'V> -> - SeqFactory<'T,'V> - end - and IdentityFactory<'T> = - class - inherit SeqFactory<'T,'T> - new : unit -> IdentityFactory<'T> - static member Instance : SeqFactory<'T,'T> - end - and Map2FirstFactory<'First,'Second,'U> = - class - inherit SeqFactory<'First,'U> - new : map:('First -> 'Second -> 'U) * - input2:IEnumerable<'Second> -> - Map2FirstFactory<'First,'Second,'U> - end - and Map2SecondFactory<'First,'Second,'U> = - class - inherit SeqFactory<'Second,'U> - new : map:('First -> 'Second -> 'U) * - input1:IEnumerable<'First> -> - Map2SecondFactory<'First,'Second,'U> - end - and Map3Factory<'First,'Second,'Third,'U> = - class - inherit SeqFactory<'First,'U> - new : map:('First -> 'Second -> 'Third -> 'U) * - input2:IEnumerable<'Second> * - input3:IEnumerable<'Third> -> - Map3Factory<'First,'Second,'Third,'U> - end - and Mapi2Factory<'First,'Second,'U> = - class - inherit SeqFactory<'First,'U> - new : map:(int -> 'First -> 'Second -> 'U) * - input2:IEnumerable<'Second> -> - Mapi2Factory<'First,'Second,'U> - end - and ISkipping = - interface - abstract member Skipping : unit -> bool - end - - and Map2First<'First,'Second,'U,'V> = - class - inherit ConsumerChainedWithCleanup<'First,'V> - new : map:('First -> 'Second -> 'U) * - enumerable2:IEnumerable<'Second> * - outOfBand: IOutOfBand * - next: Consumer<'U,'V> * pipeIdx:int -> - Map2First<'First,'Second,'U,'V> - override OnDispose : unit -> unit - override ProcessNext : input:'First -> bool - end - and Map2Second<'First,'Second,'U,'V> = - class - inherit ConsumerChainedWithCleanup<'Second,'V> - new : map:('First -> 'Second -> 'U) * - enumerable1:IEnumerable<'First> * - outOfBand: IOutOfBand * - next: Consumer<'U,'V> * pipeIdx:int -> - Map2Second<'First,'Second,'U,'V> - override OnDispose : unit -> unit - override ProcessNext : input:'Second -> bool - end - and Map3<'First,'Second,'Third,'U,'V> = - class - inherit ConsumerChainedWithCleanup<'First,'V> - new : map:('First -> 'Second -> 'Third -> 'U) * - enumerable2:IEnumerable<'Second> * - enumerable3:IEnumerable<'Third> * - outOfBand: IOutOfBand * - next: Consumer<'U,'V> * pipeIdx:int -> - Map3<'First,'Second,'Third,'U,'V> - override OnDispose : unit -> unit - override ProcessNext : input:'First -> bool - end - and Mapi2<'First,'Second,'U,'V> = - class - inherit ConsumerChainedWithCleanup<'First,'V> - new : map:(int -> 'First -> 'Second -> 'U) * - enumerable2:IEnumerable<'Second> * - outOfBand: IOutOfBand * - next: Consumer<'U,'V> * pipeIdx:int -> - Mapi2<'First,'Second,'U,'V> - override OnDispose : unit -> unit - override ProcessNext : input:'First -> bool - end - type SeqProcessNextStates = - | InProcess = 0 - | NotStarted = 1 - | Finished = 2 - type Result<'T> = - class - interface IOutOfBand - new : unit -> Result<'T> - member Current : 'T - member HaltedIdx : int - member SeqState : SeqProcessNextStates - member Current : 'T with set - member SeqState : SeqProcessNextStates with set - end - type SetResult<'T> = - class - inherit Consumer<'T,'T> - new : result: Result<'T> -> SetResult<'T> - override ProcessNext : input:'T -> bool - end - type OutOfBand = - class - interface IOutOfBand - new : unit -> OutOfBand - member HaltedIdx : int - end - module ForEach = begin - val enumerable : + type ComposedFactory<'T,'U,'V> = + class + inherit SeqFactory<'T,'V> + private new : first: SeqFactory<'T,'U> * + second: SeqFactory<'U,'V> * + secondPipeIdx: PipeIdx -> + ComposedFactory<'T,'U,'V> + static member + Combine : first: SeqFactory<'T,'U> -> + second: SeqFactory<'U,'V> -> + SeqFactory<'T,'V> + end + and IdentityFactory<'T> = + class + inherit SeqFactory<'T,'T> + new : unit -> IdentityFactory<'T> + static member Instance : SeqFactory<'T,'T> + end + + and ISkipping = + interface + abstract member Skipping : unit -> bool + end + + type SeqProcessNextStates = + | InProcess = 0 + | NotStarted = 1 + | Finished = 2 + type Result<'T> = + class + interface IOutOfBand + new : unit -> Result<'T> + member Current : 'T + member HaltedIdx : int + member SeqState : SeqProcessNextStates + member Current : 'T with set + member SeqState : SeqProcessNextStates with set + end + type SetResult<'T> = + class + inherit Consumer<'T,'T> + new : result: Result<'T> -> SetResult<'T> + override ProcessNext : input:'T -> bool + end + type OutOfBand = + class + interface IOutOfBand + new : unit -> OutOfBand + member HaltedIdx : int + end + module ForEach = begin + val enumerable : enumerable:IEnumerable<'T> -> - outOfBand: OutOfBand -> - consumer: Consumer<'T,'U> -> unit - val array : + outOfBand: OutOfBand -> + consumer: Consumer<'T,'U> -> unit + val array : array:'T array -> - outOfBand: OutOfBand -> - consumer: Consumer<'T,'U> -> unit - val list : + outOfBand: OutOfBand -> + consumer: Consumer<'T,'U> -> unit + val list : alist:'T list -> - outOfBand: OutOfBand -> - consumer: Consumer<'T,'U> -> unit - val unfold : + outOfBand: OutOfBand -> + consumer: Consumer<'T,'U> -> unit + val unfold : generator:('S -> ('T * 'S) option) -> - state:'S -> - outOfBand: OutOfBand -> - consumer: Consumer<'T,'U> -> unit - val makeIsSkipping : + state:'S -> + outOfBand: OutOfBand -> + consumer: Consumer<'T,'U> -> unit + val makeIsSkipping : consumer: Consumer<'T,'U> -> (unit -> bool) - val init : + val init : f:(int -> 'T) -> - terminatingIdx:int -> - outOfBand: OutOfBand -> - consumer: Consumer<'T,'U> -> unit - val execute : + terminatingIdx:int -> + outOfBand: OutOfBand -> + consumer: Consumer<'T,'U> -> unit + val execute : f:((unit -> unit) -> 'a) -> - current: SeqFactory<'T,'U> -> - executeOn:( OutOfBand -> Consumer<'T,'U> -> - unit) -> 'a when 'a :> Consumer<'U,'U> - end - module Enumerable = begin - type Empty<'T> = + current: SeqFactory<'T,'U> -> + executeOn:( OutOfBand -> Consumer<'T,'U> -> + unit) -> 'a when 'a :> Consumer<'U,'U> + end + module Enumerable = begin + type Empty<'T> = class - interface IDisposable - interface IEnumerator - interface IEnumerator<'T> - new : unit -> Empty<'T> - end - type EmptyEnumerators<'T> = + interface IDisposable + interface IEnumerator + interface IEnumerator<'T> + new : unit -> Empty<'T> + end + type EmptyEnumerators<'T> = class - new : unit -> EmptyEnumerators<'T> - static member Element : IEnumerator<'T> - end - [] - type EnumeratorBase<'T> = + new : unit -> EmptyEnumerators<'T> + static member Element : IEnumerator<'T> + end + [] + type EnumeratorBase<'T> = class - interface IEnumerator<'T> - interface IEnumerator - interface IDisposable - new : result: Result<'T> * - seqComponent: ICompletionChain -> - EnumeratorBase<'T> - end - and [] EnumerableBase<'T> = + interface IEnumerator<'T> + interface IEnumerator + interface IDisposable + new : result: Result<'T> * + seqComponent: ICompletionChain -> + EnumeratorBase<'T> + end + and [] EnumerableBase<'T> = class - interface ISeq<'T> - interface IEnumerable<'T> - interface IEnumerable - new : unit -> EnumerableBase<'T> - abstract member + interface ISeq<'T> + interface IEnumerable<'T> + interface IEnumerable + new : unit -> EnumerableBase<'T> + abstract member Append : seq<'T> -> IEnumerable<'T> - override + override Append : source:seq<'T> -> IEnumerable<'T> - end - and Enumerator<'T,'U> = + end + and Enumerator<'T,'U> = class - inherit EnumeratorBase<'U> - interface IDisposable - interface IEnumerator - new : source:IEnumerator<'T> * - seqComponent: Consumer<'T,'U> * - result: Result<'U> -> - Enumerator<'T,'U> - end - and Enumerable<'T,'U> = + inherit EnumeratorBase<'U> + interface IDisposable + interface IEnumerator + new : source:IEnumerator<'T> * + seqComponent: Consumer<'T,'U> * + result: Result<'U> -> + Enumerator<'T,'U> + end + and Enumerable<'T,'U> = class - inherit EnumerableBase<'U> - interface ISeq<'U> - interface IEnumerable<'U> - new : enumerable:IEnumerable<'T> * - current: SeqFactory<'T,'U> -> - Enumerable<'T,'U> - end - and ConcatEnumerator<'T,'Collection when 'Collection :> seq<'T>> = + inherit EnumerableBase<'U> + interface ISeq<'U> + interface IEnumerable<'U> + new : enumerable:IEnumerable<'T> * + current: SeqFactory<'T,'U> -> + Enumerable<'T,'U> + end + and ConcatEnumerator<'T,'Collection when 'Collection :> seq<'T>> = class - interface IDisposable - interface IEnumerator - interface IEnumerator<'T> - new : sources:seq<'Collection> -> - ConcatEnumerator<'T,'Collection> - end - and AppendEnumerable<'T> = + interface IDisposable + interface IEnumerator + interface IEnumerator<'T> + new : sources:seq<'Collection> -> + ConcatEnumerator<'T,'Collection> + end + and AppendEnumerable<'T> = class - inherit EnumerableBase<'T> - interface ISeq<'T> - interface IEnumerable<'T> - new : sources:seq<'T> list -> AppendEnumerable<'T> - override + inherit EnumerableBase<'T> + interface ISeq<'T> + interface IEnumerable<'T> + new : sources:seq<'T> list -> AppendEnumerable<'T> + override Append : source:seq<'T> -> - IEnumerable<'T> - end - and ConcatEnumerable<'T,'Collection when 'Collection :> seq<'T>> = + IEnumerable<'T> + end + and ConcatEnumerable<'T,'Collection when 'Collection :> seq<'T>> = class - inherit EnumerableBase<'T> - interface ISeq<'T> - interface IEnumerable<'T> - new : sources:seq<'Collection> -> - ConcatEnumerable<'T,'Collection> - end - val create : - enumerable:IEnumerable<'a> -> - current: SeqFactory<'a,'b> -> ISeq<'b> + inherit EnumerableBase<'T> + interface ISeq<'T> + interface IEnumerable<'T> + new : sources:seq<'Collection> -> + ConcatEnumerable<'T,'Collection> end - module EmptyEnumerable = begin - type Enumerable<'T> = + val create : + enumerable:IEnumerable<'a> -> + current: SeqFactory<'a,'b> -> ISeq<'b> + end + module EmptyEnumerable = begin + type Enumerable<'T> = class - inherit Enumerable.EnumerableBase<'T> - interface ISeq<'T> - interface IEnumerable<'T> - new : unit -> Enumerable<'T> - override + inherit Enumerable.EnumerableBase<'T> + interface ISeq<'T> + interface IEnumerable<'T> + new : unit -> Enumerable<'T> + override Append : source:seq<'T> -> IEnumerable<'T> - static member Instance : ISeq<'T> - end + static member Instance : ISeq<'T> end - module Array = begin - type Enumerator<'T,'U> = + end + module Array = begin + type Enumerator<'T,'U> = class - inherit Enumerable.EnumeratorBase<'U> - interface IEnumerator - new : delayedArray:(unit -> 'T array) * - seqComponent: Consumer<'T,'U> * - result: Result<'U> -> Enumerator<'T,'U> - end - type Enumerable<'T,'U> = + inherit Enumerable.EnumeratorBase<'U> + interface IEnumerator + new : delayedArray:(unit -> 'T array) * + seqComponent: Consumer<'T,'U> * + result: Result<'U> -> Enumerator<'T,'U> + end + type Enumerable<'T,'U> = class - inherit Enumerable.EnumerableBase<'U> - interface ISeq<'U> - interface IEnumerable<'U> - new : delayedArray:(unit -> 'T array) * - current: SeqFactory<'T,'U> -> - Enumerable<'T,'U> - end - val createDelayed : + inherit Enumerable.EnumerableBase<'U> + interface ISeq<'U> + interface IEnumerable<'U> + new : delayedArray:(unit -> 'T array) * + current: SeqFactory<'T,'U> -> + Enumerable<'T,'U> + end + val createDelayed : delayedArray:(unit -> 'T array) -> - current: SeqFactory<'T,'U> -> ISeq<'U> - val create : + current: SeqFactory<'T,'U> -> ISeq<'U> + val create : array:'T array -> - current: SeqFactory<'T,'U> -> ISeq<'U> - val createDelayedId : + current: SeqFactory<'T,'U> -> ISeq<'U> + val createDelayedId : delayedArray:(unit -> 'T array) -> ISeq<'T> - val createId : array:'T array -> ISeq<'T> - end - module List = begin - type Enumerator<'T,'U> = + val createId : array:'T array -> ISeq<'T> + end + module List = begin + type Enumerator<'T,'U> = class - inherit Enumerable.EnumeratorBase<'U> - interface IEnumerator - new : alist:'T list * seqComponent: Consumer<'T,'U> * - result: Result<'U> -> Enumerator<'T,'U> - end - type Enumerable<'T,'U> = + inherit Enumerable.EnumeratorBase<'U> + interface IEnumerator + new : alist:'T list * seqComponent: Consumer<'T,'U> * + result: Result<'U> -> Enumerator<'T,'U> + end + type Enumerable<'T,'U> = class - inherit Enumerable.EnumerableBase<'U> - interface ISeq<'U> - interface IEnumerable<'U> - new : alist:'T list * current: SeqFactory<'T,'U> -> - Enumerable<'T,'U> - end - val create : - alist:'a list -> - current: SeqFactory<'a,'b> -> ISeq<'b> + inherit Enumerable.EnumerableBase<'U> + interface ISeq<'U> + interface IEnumerable<'U> + new : alist:'T list * current: SeqFactory<'T,'U> -> + Enumerable<'T,'U> end - module Unfold = begin - type Enumerator<'T,'U,'State> = + val create : + alist:'a list -> + current: SeqFactory<'a,'b> -> ISeq<'b> + end + module Unfold = begin + type Enumerator<'T,'U,'State> = class - inherit Enumerable.EnumeratorBase<'U> - interface IEnumerator - new : generator:('State -> ('T * 'State) option) * state:'State * - seqComponent: Consumer<'T,'U> * - result: Result<'U> -> - Enumerator<'T,'U,'State> - end - type Enumerable<'T,'U,'GeneratorState> = + inherit Enumerable.EnumeratorBase<'U> + interface IEnumerator + new : generator:('State -> ('T * 'State) option) * state:'State * + seqComponent: Consumer<'T,'U> * + result: Result<'U> -> + Enumerator<'T,'U,'State> + end + type Enumerable<'T,'U,'GeneratorState> = class - inherit Enumerable.EnumerableBase<'U> - interface ISeq<'U> - interface IEnumerable<'U> - new : generator:('GeneratorState -> ('T * 'GeneratorState) option) * - state:'GeneratorState * current: SeqFactory<'T,'U> -> - Enumerable<'T,'U,'GeneratorState> - end + inherit Enumerable.EnumerableBase<'U> + interface ISeq<'U> + interface IEnumerable<'U> + new : generator:('GeneratorState -> ('T * 'GeneratorState) option) * + state:'GeneratorState * current: SeqFactory<'T,'U> -> + Enumerable<'T,'U,'GeneratorState> end - module Init = begin - val getTerminatingIdx : count:Nullable -> int - type Enumerator<'T,'U> = + end + module Init = begin + val getTerminatingIdx : count:Nullable -> int + type Enumerator<'T,'U> = class - inherit Enumerable.EnumeratorBase<'U> - interface IEnumerator - new : count:Nullable * f:(int -> 'T) * - seqComponent: Consumer<'T,'U> * - result: Result<'U> -> Enumerator<'T,'U> - end - type Enumerable<'T,'U> = + inherit Enumerable.EnumeratorBase<'U> + interface IEnumerator + new : count:Nullable * f:(int -> 'T) * + seqComponent: Consumer<'T,'U> * + result: Result<'U> -> Enumerator<'T,'U> + end + type Enumerable<'T,'U> = class - inherit Enumerable.EnumerableBase<'U> - interface ISeq<'U> - interface IEnumerable<'U> - new : count:Nullable * f:(int -> 'T) * - current: SeqFactory<'T,'U> -> - Enumerable<'T,'U> - end - val upto : + inherit Enumerable.EnumerableBase<'U> + interface ISeq<'U> + interface IEnumerable<'U> + new : count:Nullable * f:(int -> 'T) * + current: SeqFactory<'T,'U> -> + Enumerable<'T,'U> + end + val upto : lastOption:int option -> - f:(int -> 'U) -> IEnumerator<'U> - type EnumerableDecider<'T> = + f:(int -> 'U) -> IEnumerator<'U> + type EnumerableDecider<'T> = class - inherit Enumerable.EnumerableBase<'T> - interface ISeq<'T> - interface IEnumerable<'T> - new : count:Nullable * f:(int -> 'T) -> - EnumerableDecider<'T> - end + inherit Enumerable.EnumerableBase<'T> + interface ISeq<'T> + interface IEnumerable<'T> + new : count:Nullable * f:(int -> 'T) -> + EnumerableDecider<'T> end + end + + [] + val toComposer : source:seq<'T> -> ISeq<'T> + + val inline foreach : f:((unit -> unit) -> 'a) -> source: ISeq<'b> -> 'a when 'a :> Consumer<'b,'b> + + [] + val inline average : source: ISeq< ^T> -> ^T + when 'T:(static member Zero : ^T) + and 'T:(static member (+) : ^T * ^T -> ^T) + and ^T:(static member DivideByInt : ^T * int -> ^T) + + [] + val inline averageBy : f:('T -> ^U) -> source:ISeq< 'T > -> ^U + when ^U:(static member Zero : ^U) + and ^U:(static member (+) : ^U * ^U -> ^U) + and ^U:(static member DivideByInt : ^U * int -> ^U) + + [] + val empty<'T> : ISeq<'T> + + [] + val inline exactlyOne : errorString:string -> source : ISeq<'T> -> 'T + + [] + val inline fold<'T,'State> : f:('State->'T->'State) -> seed:'State -> source:ISeq<'T> -> 'State + + [] + val inline fold2<'T1,'T2,'State> : folder:('State->'T1->'T2->'State) -> state:'State -> source1: ISeq<'T1> -> source2: ISeq<'T2> -> 'State + + [] + val unfold : generator:('State -> ('T * 'State) option) -> state:'State -> ISeq<'T> + + [] + val initInfinite : f:(int -> 'T) -> ISeq<'T> + + [] + val init : count:int -> f:(int -> 'T) -> ISeq<'T> + + [] + val iter : f:('T -> unit) -> source: ISeq<'T> -> unit + + [] + val inline iter2 : f:('T->'U->unit) -> source1 : ISeq<'T> -> source2 : ISeq<'U> -> unit + + [] + val inline iteri2 : f:(int->'T->'U->unit) -> source1:ISeq<'T> -> source2:seq<'U> -> unit + + [] + val tryHead : source: ISeq<'T> -> 'T option + + [] + val iteri : f:(int -> 'T -> unit) -> source: ISeq<'T> -> unit + + [] + val inline except : itemsToExclude:seq<'T> -> source:ISeq<'T> -> ISeq<'T> when 'T:equality + + [] + val exists : f:('T -> bool) -> source: ISeq<'T> -> bool + + [] + val exists2 : predicate:('T->'U->bool) -> source1:ISeq<'T> -> source2:ISeq<'U> -> bool + + [] + val inline contains : element:'T -> source: ISeq<'T> -> bool when 'T : equality + + [] + val forall : f:('T -> bool) -> source: ISeq<'T> -> bool - [] - val toComposer : source:seq<'T> -> ISeq<'T> + [] + val inline forall2 : predicate:('T->'U->bool) -> source1:ISeq<'T> -> source2:ISeq<'U> -> bool - val inline foreach : f:((unit -> unit) -> 'a) -> source: ISeq<'b> -> 'a when 'a :> Consumer<'b,'b> + [] + val inline filter : f:('T -> bool) -> source: ISeq<'T> -> ISeq<'T> - [] - val empty<'T> : ISeq<'T> + [] + val inline map : f:('T -> 'U) -> source: ISeq<'T> -> ISeq<'U> - [] - val unfold : generator:('State -> ('T * 'State) option) -> state:'State -> ISeq<'T> + [] + val inline mapi : f:(int->'a->'b) -> source: ISeq<'a> -> ISeq<'b> - [] - val initInfinite : f:(int -> 'T) -> ISeq<'T> + [] + val inline map2<'First,'Second,'U> : map:('First->'Second->'U) -> source1:ISeq<'First> -> source2:ISeq<'Second> -> ISeq<'U> - [] - val init : count:int -> f:(int -> 'T) -> ISeq<'T> + [] + val inline mapi2<'First,'Second,'U> : map:(int -> 'First->'Second->'U) -> source1:ISeq<'First> -> source2:ISeq<'Second> -> ISeq<'U> - [] - val iter : f:('T -> unit) -> source: ISeq<'T> -> unit + [] + val inline map3<'First,'Second,'Third,'U> : map:('First->'Second->'Third->'U) -> source1:ISeq<'First> -> source2:ISeq<'Second> -> source3:ISeq<'Third> -> ISeq<'U> - [] - val tryHead : source: ISeq<'T> -> 'T option + [] + val inline compareWith : f:('T -> 'T -> int) -> source1 :ISeq<'T> -> source2:ISeq<'T> -> int - [] - val iteri : f:(int -> 'T -> unit) -> source: ISeq<'T> -> unit + [] + val inline choose : f:('a->option<'b>) -> source: ISeq<'a> -> ISeq<'b> - [] - val inline except : itemsToExclude:seq<'T> -> source:ISeq<'T> -> ISeq<'T> when 'T:equality + [] + val inline distinct : source: ISeq<'T> -> ISeq<'T> when 'T:equality - [] - val exists : f:('T -> bool) -> source: ISeq<'T> -> bool + [] + val inline distinctBy : keyf:('T->'Key) -> source: ISeq<'T> -> ISeq<'T> when 'Key:equality - [] - val inline contains : element:'T -> source: ISeq<'T> -> bool when 'T : equality + [] + val inline max : source: ISeq<'T> -> 'T when 'T:comparison - [] - val forall : f:('T -> bool) -> source: ISeq<'T> -> bool + [] + val inline maxBy : f:('T -> 'U) -> source: ISeq<'T> -> 'T when 'U:comparison - [] - val inline filter : f:('T -> bool) -> source: ISeq<'T> -> ISeq<'T> + [] + val inline min : source: ISeq<'T> -> 'T when 'T:comparison - [] - val inline map : f:('T -> 'U) -> source: ISeq<'T> -> ISeq<'U> + [] + val inline minBy : f:('T -> 'U) -> source: ISeq<'T> -> 'T when 'U:comparison - [] - val inline mapi : f:(int->'a->'b) -> source: ISeq<'a> -> ISeq<'b> + [] + val inline pairwise : source:ISeq<'T> -> ISeq<'T * 'T> - val mapi_adapt : f:OptimizedClosures.FSharpFunc -> source: ISeq<'a> -> ISeq<'b> + [] + val inline reduce : f:('T->'T->'T) -> source: ISeq<'T> -> 'T - [] - val inline choose : f:('a->option<'b>) -> source: ISeq<'a> -> ISeq<'b> + [] + val inline scan : folder:('State->'T->'State) -> initialState:'State -> source:ISeq<'T> -> ISeq<'State> - [] - val inline distinct : source: ISeq<'T> -> ISeq<'T> when 'T:equality + [] + val inline skip : errorString:string -> skipCount:int -> source:ISeq<'T> -> ISeq<'T> - [] - val inline distinctBy : keyf:('T->'Key) -> source: ISeq<'T> -> ISeq<'T> when 'Key:equality + [] + val inline skipWhile : predicate:('T->bool) -> source:ISeq<'T> -> ISeq<'T> - [] - val inline pairwise : source:ISeq<'T> -> ISeq<'T * 'T> + [] + val inline sum : source:ISeq<'T> -> 'T + when 'T:(static member Zero : ^T) + and 'T:(static member (+) : ^T * ^T -> ^T) - [] - val inline scan : folder:('State->'T->'State) -> initialState:'State -> source:ISeq<'T> -> ISeq<'State> + [] + val inline sumBy : f :('T -> ^U) -> source: ISeq<'T> -> ^U + when ^U:(static member Zero : ^U) + and ^U:(static member (+) : ^U * ^U -> ^U) - [] - val inline skip : skipCount:int -> source:ISeq<'T> -> ISeq<'T> + [] + val inline take : errorString:string -> takeCount:int -> source:ISeq<'T> -> ISeq<'T> - [] - val inline skipWhile : predicate:('T->bool) -> source:ISeq<'T> -> ISeq<'T> + [] + val inline takeWhile : predicate:('T->bool) -> source:ISeq<'T> -> ISeq<'T> - [] - val inline take : takeCount:int -> source:ISeq<'T> -> ISeq<'T> + [] + val inline tail : errorString:string -> source:ISeq<'T> -> ISeq<'T> - [] - val inline takeWhile : predicate:('T->bool) -> source:ISeq<'T> -> ISeq<'T> + [] + val inline truncate : truncateCount:int -> source:ISeq<'T> -> ISeq<'T> - [] - val inline tail : source:ISeq<'T> -> ISeq<'T> + [] + val inline indexed : source: ISeq<'a> -> ISeq - [] - val inline truncate : truncateCount:int -> source:ISeq<'T> -> ISeq<'T> + [] + val tryItem : errorString:string -> index:int -> source: ISeq<'T> -> 'T option - [] - val inline indexed : source: ISeq<'a> -> ISeq + [] + val tryPick : f:('T -> 'U option) -> source: ISeq<'T> -> Option<'U> - [] - val tryItem : index:int -> source: ISeq<'T> -> 'T option + [] + val tryFind : f:('T -> bool) -> source: ISeq<'T> -> Option<'T> - [] - val tryPick : f:('T -> 'U option) -> source: ISeq<'T> -> Option<'U> + [] + val inline tryFindIndex: preidcate:('T->bool) -> source:ISeq<'T> -> int option - [] - val tryFind : f:('T -> bool) -> source: ISeq<'T> -> Option<'T> + [] + val inline tryLast : source:ISeq<'T> -> 'T option - [] - val inline windowed : windowSize:int -> source:ISeq<'T> -> ISeq<'T[]> + [] + val inline windowed : windowSize:int -> source:ISeq<'T> -> ISeq<'T[]> From 5fa42353c040c940e7473520ca8c91d518b390b6 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Thu, 15 Dec 2016 09:17:42 +0100 Subject: [PATCH 56/59] Removed ICompletionChain Just made it into a abstract class at the top of the hierarchy Removed unnecessary SetResult type Wrapped it's functionality into Result type Fix iteri2 from seq to ISeq Renaming Value to State Modified Folder to contain Result - This simplified foreach to allow for some further optimizations Moved IOutOfBound into Folder - Avoid creating extra object - foreach implementations call StopFutureProcessing directly Added Upcast for IOutOfBand Added *Thin for when no transforms applied Moved OnComplete Dipose() to OnDispose - fixed some consistency around member & override "Inline" ForEach methods - via struct interface (i.e. inline at runtime) - basically speed parity for sum Shrinking signature file Removed foreach/compose helpers - the didn't really serve any purpose Renamed ForEach to Fold Removed PipeIdx from SeqFactory - Made management of it part of the ISeq classes - Removed internal Build function as well Made Fold iterators more consistent Renamed Consumer to Activity - didn't really consume anything - removed helper classes to slightly decrease surface area Removed errorString argument - Moved SR.GetString code into Composer better selection of inline function Simplified inheritence hierarchy - and finally decided to just go with Transform as the general name for processing Restored TransformWithPostProcessing hierarch - For symmetry with Folder - Fixed a spelling error More renaming - SeqFactory to TransformFactory - Compose to PushTransform - Create to Compose Fix Skipping logic on Fold - And removed unbox cast for performance Made "Upcast"s little safer Tring to make variable naming consistent Consistency work; naming, spacing Composer.groupBy(Ref|Val) Fixed constraint (applied on wrong argument) Added module for GroupBy - also renamed delayed as delay to match seq Moved Array based function to Composer sorts/rev/permute ToArray via Fold - and moved creating Value comparer to a helper function null checks handled in toComposer countBy Remove comented minValBy/maxValBy head/last into Composer - more consistency formatting --- src/fsharp/FSharp.Core/seq.fs | 251 +--- src/fsharp/FSharp.Core/seqcomposer.fs | 1802 +++++++++++++----------- src/fsharp/FSharp.Core/seqcomposer.fsi | 516 ++----- 3 files changed, 1149 insertions(+), 1420 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index c5adc43ac6f..ab333fe3e0b 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -46,18 +46,12 @@ namespace Microsoft.FSharp.Collections [] let toComposer (source:seq<'T>): Composer.Core.ISeq<'T> = - Composer.toComposer source - - let inline foreach f (source:seq<_>) = - Composer.foreach f (toComposer source) + checkNonNull "source" source + Composer.ofSeq source - let private seqFactory (createSeqComponent:#SeqFactory<_,_>) (source:seq<'T>) = - match source with - | :? Composer.Core.ISeq<'T> as s -> Upcast.enumerable (s.Compose createSeqComponent) - | :? array<'T> as a -> Upcast.enumerable (Composer.Array.create a createSeqComponent) - | :? list<'T> as a -> Upcast.enumerable (Composer.List.create a createSeqComponent) - | null -> nullArg "source" - | _ -> Upcast.enumerable (Composer.Enumerable.create source createSeqComponent) + let toComposer' name (source:seq<'T>): Composer.Core.ISeq<'T> = + checkNonNull name source + Composer.ofSeq source [] let delay f = mkDelayedSeq f @@ -91,7 +85,7 @@ namespace Microsoft.FSharp.Collections [] let skip count (source: seq<_>) = source |> toComposer - |> Composer.skip (SR.GetString SR.notEnoughElements) count |> Upcast.enumerable + |> Composer.skip count |> Upcast.enumerable let invalidArgumnetIndex = invalidArgFmt "index" @@ -99,7 +93,7 @@ namespace Microsoft.FSharp.Collections let item i (source : seq<'T>) = if i < 0 then invalidArgInputMustBeNonNegative "index" i else source - |> toComposer |> Composer.skip (SR.GetString SR.notEnoughElements) i |> Upcast.enumerable + |> toComposer |> Composer.skip i |> Upcast.enumerable |> tryHead |> function | None -> invalidArgFmt "index" "{0}\nseq was short by 1 element" [|SR.GetString SR.notEnoughElements|] @@ -107,7 +101,7 @@ namespace Microsoft.FSharp.Collections [] let tryItem i (source:seq<'T>) = - source |> toComposer |> Composer.tryItem (SR.GetString SR.notEnoughElements) i + source |> toComposer |> Composer.tryItem i [] let nth i (source : seq<'T>) = item i source @@ -131,22 +125,16 @@ namespace Microsoft.FSharp.Collections [] let iter2 (f:'T->'U->unit) (source1 : seq<'T>) (source2 : seq<'U>) = - checkNonNull "source1" source1 - checkNonNull "source2" source2 let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - (source1|>toComposer, source2|>toComposer) + (source1 |> toComposer' "source1", source2 |> toComposer' "source2") ||> Composer.iter2 (fun a b -> f.Invoke(a,b)) - [] let iteri2 (f:int->'T->'U->unit) (source1 : seq<_>) (source2 : seq<_>) = - checkNonNull "source1" source1 - checkNonNull "source2" source2 let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f) - (source1|>toComposer, source2|>toComposer) + (source1 |> toComposer' "source1", source2 |> toComposer' "source2") ||> Composer.iteri2 (fun idx a b -> f.Invoke(idx,a,b)) - // Build an IEnumerble by wrapping/transforming iterators as they get generated. let revamp f (ie : seq<_>) = mkSeq (fun () -> f (ie.GetEnumerator())) let revamp2 f (ie1 : seq<_>) (source2 : seq<_>) = @@ -172,24 +160,18 @@ namespace Microsoft.FSharp.Collections [] let mapi2 (mapfn:int->'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) = - checkNonNull "source1" source1 - checkNonNull "source2" source2 let f = OptimizedClosures.FSharpFunc.Adapt mapfn - (source1|>toComposer, source2|>toComposer) + (source1 |> toComposer' "source1", source2 |> toComposer' "source2") ||> Composer.mapi2 (fun idx a b ->f.Invoke(idx,a,b)) |> Upcast.enumerable [] let map2<'T,'U,'V> (mapfn:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> = - checkNonNull "source1" source1 - checkNonNull "source2" source2 - (source1|>toComposer, source2|>toComposer) + (source1 |> toComposer' "source1", source2 |> toComposer' "source2") ||> Composer.map2 mapfn |> Upcast.enumerable [] let map3 mapfn source1 source2 source3 = - checkNonNull "source2" source2 - checkNonNull "source3" source3 - (source1|>toComposer, source2|>toComposer, source3|>toComposer) + (source1 |> toComposer' "source1", source2 |> toComposer' "source2", source3 |> toComposer' "source3") |||> Composer.map3 mapfn |> Upcast.enumerable [] @@ -238,7 +220,7 @@ namespace Microsoft.FSharp.Collections if count < 0 then invalidArgInputMustBeNonNegative "count" count (* Note: don't create or dispose any IEnumerable if n = 0 *) if count = 0 then empty else - source |> toComposer |> Composer.take (SR.GetString SR.notEnoughElements) count |> Upcast.enumerable + source |> toComposer |> Composer.take count |> Upcast.enumerable [] let isEmpty (source : seq<'T>) = @@ -253,8 +235,7 @@ namespace Microsoft.FSharp.Collections [] let concat (sources:seq<#seq<'T>>) : seq<'T> = - checkNonNull "sources" sources - upcast Composer.Enumerable.ConcatEnumerable sources + sources |> toComposer' "sources" |> Composer.map toComposer |> Composer.concat |> Upcast.enumerable [] let length (source : seq<'T>) = @@ -279,10 +260,8 @@ namespace Microsoft.FSharp.Collections [] let fold2<'T1,'T2,'State> f (state:'State) (source1: seq<'T1>) (source2: seq<'T2>) = - checkNonNull "source1" source1 - checkNonNull "source2" source2 let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f) - (source1 |> toComposer, source2|>toComposer) + (source1 |> toComposer' "source1", source2 |> toComposer' "source2") ||> Composer.fold2(fun s a b -> f.Invoke(s,a,b)) state [] @@ -299,28 +278,20 @@ namespace Microsoft.FSharp.Collections seq { for _ in 1 .. count -> x } #endif - [] let append (source1: seq<'T>) (source2: seq<'T>) = - checkNonNull "source1" source1 - checkNonNull "source2" source2 - match source1 with - | :? Composer.Enumerable.EnumerableBase<'T> as s -> s.Append source2 - | _ -> Upcast.enumerable (new Composer.Enumerable.AppendEnumerable<_>([source2; source1])) - + (source1 |> toComposer' "source1", source2 |> toComposer' "source2") + ||> Composer.append |> Upcast.enumerable [] let collect f sources = map f sources |> concat [] let compareWith (f:'T -> 'T -> int) (source1 : seq<'T>) (source2: seq<'T>) = - checkNonNull "source1" source1 - checkNonNull "source2" source2 let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - (source1|>toComposer, source2|>toComposer) + (source1 |> toComposer' "source1", source2 |> toComposer' "source2") ||> Composer.compareWith (fun a b -> f.Invoke(a,b)) - [] let ofList (source : 'T list) = (source :> seq<'T>) @@ -334,23 +305,11 @@ namespace Microsoft.FSharp.Collections [] let ofArray (source : 'T array) = checkNonNull "source" source - Upcast.enumerable (Composer.Array.createId source) + Upcast.enumerable (Composer.ofArray source) [] let toArray (source : seq<'T>) = - checkNonNull "source" source - match source with - | :? ('T[]) as res -> (res.Clone() :?> 'T[]) - | :? ('T list) as res -> List.toArray res - | :? ICollection<'T> as res -> - // Directly create an array and copy ourselves. - // This avoids an extra copy if using ResizeArray in fallback below. - let arr = Array.zeroCreateUnchecked res.Count - res.CopyTo(arr, 0) - arr - | _ -> - let res = ResizeArray<_>(source) - res.ToArray() + source |> toComposer |> Composer.toArray let foldArraySubRight (f:OptimizedClosures.FSharpFunc<'T,_,_>) (arr: 'T[]) start fin acc = let mutable state = acc @@ -512,50 +471,20 @@ namespace Microsoft.FSharp.Collections checkNonNull "source" source mkSeq (fun () -> source.GetEnumerator()) - let inline groupByImpl (comparer:IEqualityComparer<'SafeKey>) (keyf:'T->'SafeKey) (getKey:'SafeKey->'Key) (seq:seq<'T>) = - checkNonNull "seq" seq - - let dict = Dictionary<_,ResizeArray<_>> comparer - - // Previously this was 1, but I think this is rather stingy, considering that we are already paying - // for at least a key, the ResizeArray reference, which includes an array reference, an Entry in the - // Dictionary, plus any empty space in the Dictionary of unfilled hash buckets. - let minimumBucketSize = 4 - - // Build the groupings - seq |> iter (fun v -> - let safeKey = keyf v - let mutable prev = Unchecked.defaultof<_> - match dict.TryGetValue (safeKey, &prev) with - | true -> prev.Add v - | false -> - let prev = ResizeArray () - dict.[safeKey] <- prev - prev.Add v) - - // Trim the size of each result group, don't trim very small buckets, as excessive work, and garbage for - // minimal gain - dict |> iter (fun group -> if group.Value.Count > minimumBucketSize then group.Value.TrimExcess()) - - // Return the sequence-of-sequences. Don't reveal the - // internal collections: just reveal them as sequences - dict |> map (fun group -> (getKey group.Key, readonly group.Value)) - - // We avoid wrapping a StructBox, because under 64 JIT we get some "hard" tailcalls which affect performance - let groupByValueType (keyf:'T->'Key) (seq:seq<'T>) = seq |> groupByImpl HashIdentity.Structural<'Key> keyf id - - // Wrap a StructBox around all keys in case the key type is itself a type using null as a representation - let groupByRefType (keyf:'T->'Key) (seq:seq<'T>) = seq |> groupByImpl RuntimeHelpers.StructBox<'Key>.Comparer (fun t -> RuntimeHelpers.StructBox (keyf t)) (fun sb -> sb.Value) - [] - let groupBy (keyf:'T->'Key) (seq:seq<'T>) = + let groupBy (keyf:'T->'Key) (source:seq<'T>) = + let grouped = #if FX_RESHAPED_REFLECTION - if (typeof<'Key>).GetTypeInfo().IsValueType + if (typeof<'Key>).GetTypeInfo().IsValueType #else - if typeof<'Key>.IsValueType + if typeof<'Key>.IsValueType #endif - then mkDelayedSeq (fun () -> groupByValueType keyf seq) - else mkDelayedSeq (fun () -> groupByRefType keyf seq) + then source |> toComposer |> Composer.GroupBy.byVal keyf + else source |> toComposer |> Composer.GroupBy.byRef keyf + + grouped + |> Composer.map (fun (key,value) -> key, Upcast.enumerable value) + |> Upcast.enumerable [] let distinct source = @@ -567,30 +496,15 @@ namespace Microsoft.FSharp.Collections [] let sortBy keyf source = - checkNonNull "source" source - let delayedSort () = - let array = source |> toArray - Array.stableSortInPlaceBy keyf array - array - Upcast.enumerable (Composer.Array.createDelayedId delayedSort) + source |> toComposer |> Composer.sortBy keyf |> Upcast.enumerable [] let sort source = - checkNonNull "source" source - let delayedSort () = - let array = source |> toArray - Array.stableSortInPlace array - array - Upcast.enumerable (Composer.Array.createDelayedId delayedSort) + source |> toComposer |> Composer.sort |> Upcast.enumerable [] let sortWith f source = - checkNonNull "source" source - let delayedSort () = - let array = source |> toArray - Array.stableSortInPlaceWith f array - array - Upcast.enumerable (Composer.Array.createDelayedId delayedSort) + source |> toComposer |> Composer.sortWith f |> Upcast.enumerable [] let inline sortByDescending keyf source = @@ -604,38 +518,15 @@ namespace Microsoft.FSharp.Collections let inline compareDescending a b = compare b a sortWith compareDescending source - let inline countByImpl (comparer:IEqualityComparer<'SafeKey>) (keyf:'T->'SafeKey) (getKey:'SafeKey->'Key) (source:seq<'T>) = - checkNonNull "source" source - - let dict = Dictionary comparer - - // Build the groupings - source |> iter (fun v -> - let safeKey = keyf v - let mutable prev = Unchecked.defaultof<_> - if dict.TryGetValue(safeKey, &prev) - then dict.[safeKey] <- prev + 1 - else dict.[safeKey] <- 1) - - dict |> map (fun group -> (getKey group.Key, group.Value)) - - // We avoid wrapping a StructBox, because under 64 JIT we get some "hard" tailcalls which affect performance - let countByValueType (keyf:'T->'Key) (seq:seq<'T>) = seq |> countByImpl HashIdentity.Structural<'Key> keyf id - - // Wrap a StructBox around all keys in case the key type is itself a type using null as a representation - let countByRefType (keyf:'T->'Key) (seq:seq<'T>) = seq |> countByImpl RuntimeHelpers.StructBox<'Key>.Comparer (fun t -> RuntimeHelpers.StructBox (keyf t)) (fun sb -> sb.Value) - [] let countBy (keyf:'T->'Key) (source:seq<'T>) = - checkNonNull "source" source - #if FX_RESHAPED_REFLECTION if (typeof<'Key>).GetTypeInfo().IsValueType #else if typeof<'Key>.IsValueType #endif - then mkDelayedSeq (fun () -> countByValueType keyf source) - else mkDelayedSeq (fun () -> countByRefType keyf source) + then source |> toComposer |> Composer.CountBy.byVal keyf |> Upcast.enumerable + else source |> toComposer |> Composer.CountBy.byRef keyf |> Upcast.enumerable [] let inline sum (source:seq<'a>) : 'a = @@ -660,23 +551,7 @@ namespace Microsoft.FSharp.Collections [] let inline minBy (projection: 'T -> 'U when 'U:comparison) (source: seq<'T>) : 'T = source |> toComposer |> Composer.minBy projection -(* - [] - let inline minValBy (f : 'T -> 'U) (source: seq<'T>) : 'U = - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" InputSequenceEmptyString - let first = e.Current - let mutable acc = f first - while e.MoveNext() do - let currv = e.Current - let curr = f currv - if curr < acc then - acc <- curr - acc - -*) + [] let inline max (source: seq<'T>) = source |> toComposer |> Composer.max @@ -685,23 +560,6 @@ namespace Microsoft.FSharp.Collections let inline maxBy (projection: 'T -> 'U) (source: seq<'T>) : 'T = source |> toComposer |> Composer.maxBy projection -(* - [] - let inline maxValBy (f : 'T -> 'U) (source: seq<'T>) : 'U = - checkNonNull "source" source - use e = source.GetEnumerator() - if not (e.MoveNext()) then - invalidArg "source" InputSequenceEmptyString - let first = e.Current - let mutable acc = f first - while e.MoveNext() do - let currv = e.Current - let curr = f currv - if curr > acc then - acc <- curr - acc - -*) [] let takeWhile predicate (source: seq<_>) = source |> toComposer |> Composer.takeWhile predicate |> Upcast.enumerable @@ -712,29 +570,23 @@ namespace Microsoft.FSharp.Collections [] let forall2 p (source1: seq<_>) (source2: seq<_>) = - checkNonNull "source1" source1 - checkNonNull "source2" source2 let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt p - (source1|>toComposer, source2|>toComposer) + (source1 |> toComposer' "source1", source2 |> toComposer' "source2") ||> Composer.forall2 (fun a b -> p.Invoke(a,b)) [] let exists2 p (source1: seq<_>) (source2: seq<_>) = - checkNonNull "source1" source1 - checkNonNull "source2" source2 let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt p - (source1|>toComposer, source2|>toComposer) + (source1 |> toComposer' "source1", source2 |> toComposer' "source2") ||> Composer.exists2 (fun a b -> p.Invoke(a,b)) [] let head (source : seq<_>) = - match tryHead source with - | None -> invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - | Some x -> x + source |> toComposer |> Composer.head [] let tail (source: seq<'T>) = - source |> toComposer |> Composer.tail (SR.GetString SR.notEnoughElements) |> Upcast.enumerable + source |> toComposer |> Composer.tail |> Upcast.enumerable [] let tryLast (source : seq<_>) = @@ -742,13 +594,11 @@ namespace Microsoft.FSharp.Collections [] let last (source : seq<_>) = - match tryLast source with - | None -> invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - | Some x -> x + source |> toComposer |> Composer.last [] let exactlyOne (source : seq<_>) = - source |> toComposer |> Composer.exactlyOne (SR.GetString(SR.inputSequenceTooLong)) + source |> toComposer |> Composer.exactlyOne member this.OnComplete _ = if this.Value._1 then @@ -759,21 +609,11 @@ namespace Microsoft.FSharp.Collections [] let rev source = - checkNonNull "source" source - let delayedReverse () = - let array = source |> toArray - Array.Reverse array - array - Upcast.enumerable (Composer.Array.createDelayedId delayedReverse) + source |> toComposer |> Composer.rev |> Upcast.enumerable [] let permute f (source:seq<_>) = - checkNonNull "source" source - let delayedPermute () = - source - |> toArray - |> Array.permute f - Upcast.enumerable (Composer.Array.createDelayedId delayedPermute) + source |> toComposer |> Composer.permute f |> Upcast.enumerable [] let mapFold<'T,'State,'Result> (f: 'State -> 'T -> 'Result * 'State) acc source = @@ -790,7 +630,6 @@ namespace Microsoft.FSharp.Collections [] let except (itemsToExclude: seq<'T>) (source: seq<'T>) = - checkNonNull "itemsToExclude" itemsToExclude if isEmpty itemsToExclude then source else source |> toComposer |> Composer.except itemsToExclude |> Upcast.enumerable diff --git a/src/fsharp/FSharp.Core/seqcomposer.fs b/src/fsharp/FSharp.Core/seqcomposer.fs index bbc6ab3cdf9..0026fa3a2b8 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fs +++ b/src/fsharp/FSharp.Core/seqcomposer.fs @@ -23,11 +23,15 @@ namespace Microsoft.FSharp.Collections [] type NoValue = struct end + [] + type Value<'a> = + val mutable _1 : 'a + new (a:'a) = { _1 = a } + [] type Values<'a,'b> = val mutable _1 : 'a val mutable _2 : 'b - new (a:'a, b: 'b) = { _1 = a; _2 = b } [] @@ -35,7 +39,6 @@ namespace Microsoft.FSharp.Collections val mutable _1 : 'a val mutable _2 : 'b val mutable _3 : 'c - new (a:'a, b:'b, c:'c) = { _1 = a; _2 = b; _3 = c } type PipeIdx = int @@ -43,96 +46,90 @@ namespace Microsoft.FSharp.Collections type IOutOfBand = abstract StopFurtherProcessing : PipeIdx -> unit - type ICompletionChain = + [] + type Activity() = abstract ChainComplete : stopTailCall:byref * PipeIdx -> unit abstract ChainDispose : stopTailCall:byref -> unit [] - type Consumer<'T,'U> () = + type Activity<'T,'U> () = + inherit Activity() abstract ProcessNext : input:'T -> bool - interface ICompletionChain with - member this.ChainComplete (_,_) = () - member this.ChainDispose _ = () - - [] - type ConsumerWithState<'T,'U,'Value> = - inherit Consumer<'T,'U> - - val mutable Value : 'Value - - new (init) = { - Value = init - } - [] - type ConsumerChainedWithState<'T,'U,'Value> = - inherit ConsumerWithState<'T,'U,'Value> - - val private Next : ICompletionChain - - new (next:ICompletionChain, init) = { - inherit ConsumerWithState<'T,'U,'Value> (init) + type Transform<'T,'U,'State> = + inherit Activity<'T,'U> + + new (next:Activity, initState:'State) = { + inherit Activity<'T,'U> () + State = initState Next = next } - interface ICompletionChain with - member this.ChainComplete (stopTailCall, terminatingIdx) = - this.Next.ChainComplete (&stopTailCall, terminatingIdx) - member this.ChainDispose stopTailCall = - this.Next.ChainDispose (&stopTailCall) - - [] - type ConsumerChained<'T,'U>(next:ICompletionChain) = - inherit ConsumerChainedWithState<'T,'U,NoValue>(next, Unchecked.defaultof) + val mutable State : 'State + val Next : Activity + + override this.ChainComplete (stopTailCall, terminatingIdx) = + this.Next.ChainComplete (&stopTailCall, terminatingIdx) + override this.ChainDispose stopTailCall = + this.Next.ChainDispose (&stopTailCall) [] - type ConsumerChainedWithStateAndCleanup<'T,'U,'Value> (next, init) = - inherit ConsumerChainedWithState<'T,'U,'Value>(next, init) + type TransformWithPostProcessing<'T,'U,'State>(next:Activity, initState:'State) = + inherit Transform<'T,'U,'State>(next, initState) abstract OnComplete : PipeIdx -> unit abstract OnDispose : unit -> unit - interface ICompletionChain with - member this.ChainComplete (stopTailCall, terminatingIdx) = - this.OnComplete terminatingIdx - next.ChainComplete (&stopTailCall, terminatingIdx) - member this.ChainDispose stopTailCall = - try this.OnDispose () - finally next.ChainDispose (&stopTailCall) + override this.ChainComplete (stopTailCall, terminatingIdx) = + this.OnComplete terminatingIdx + this.Next.ChainComplete (&stopTailCall, terminatingIdx) + override this.ChainDispose stopTailCall = + try this.OnDispose () + finally this.Next.ChainDispose (&stopTailCall) [] - type ConsumerChainedWithCleanup<'T,'U>(next:ICompletionChain) = - inherit ConsumerChainedWithStateAndCleanup<'T,'U,NoValue>(next, Unchecked.defaultof) + type Folder<'T,'Result,'State> = + inherit Activity<'T,'T> + + val mutable Result : 'Result + val mutable State : 'State + + val mutable HaltedIdx : int + member this.StopFurtherProcessing pipeIdx = this.HaltedIdx <- pipeIdx + interface IOutOfBand with + member this.StopFurtherProcessing pipeIdx = this.StopFurtherProcessing pipeIdx + + new (initalResult,initState) = { + inherit Activity<'T,'T>() + State = initState + HaltedIdx = 0 + Result = initalResult + } - [] - type Folder<'T,'U>(init) = - inherit ConsumerWithState<'T,'T,'U>(init) + override this.ChainComplete (_,_) = () + override this.ChainDispose _ = () [] - type FolderWithOnComplete<'T, 'U>(init) = - inherit Folder<'T,'U>(init) + type FolderWithPostProcessing<'T,'Result,'State>(initResult,initState) = + inherit Folder<'T,'Result,'State>(initResult,initState) abstract OnComplete : PipeIdx -> unit + abstract OnDispose : unit -> unit - interface ICompletionChain with - member this.ChainComplete (stopTailCall, terminatingIdx) = - this.OnComplete terminatingIdx - member this.ChainDispose _ = () + override this.ChainComplete (stopTailCall, terminatingIdx) = + this.OnComplete terminatingIdx + override this.ChainDispose _ = + this.OnDispose () [] - type SeqFactory<'T,'U> () = - abstract PipeIdx : PipeIdx - abstract Create<'V> : IOutOfBand -> PipeIdx -> Consumer<'U,'V> -> Consumer<'T,'V> - - default __.PipeIdx = 1 - - member this.Build outOfBand next = this.Create outOfBand 1 next + type TransformFactory<'T,'U> () = + abstract Compose<'V> : IOutOfBand -> PipeIdx -> Activity<'U,'V> -> Activity<'T,'V> type ISeq<'T> = inherit IEnumerable<'T> - abstract member Compose<'U> : (SeqFactory<'T,'U>) -> ISeq<'U> - abstract member ForEach<'consumer when 'consumer :> Consumer<'T,'T>> : f:((unit->unit)->'consumer) -> 'consumer + abstract member PushTransform<'U> : TransformFactory<'T,'U> -> ISeq<'U> + abstract member Fold<'Result,'State> : f:(PipeIdx->Folder<'T,'Result,'State>) -> 'Result open Core @@ -145,35 +142,40 @@ namespace Microsoft.FSharp.Collections module internal Upcast = // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality // is fixed with the compiler then these functions can be removed. - let inline seq (t:#ISeq<'T>) : ISeq<'T> = (# "" t : ISeq<'T> #) - let inline enumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) - let inline enumerator (t:#IEnumerator<'T>) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) - let inline enumeratorNonGeneric (t:#IEnumerator) : IEnumerator = (# "" t : IEnumerator #) - let inline iCompletionChain (t:#ICompletionChain) : ICompletionChain = (# "" t : ICompletionChain #) - - - type ComposedFactory<'T,'U,'V> private (first:SeqFactory<'T,'U>, second:SeqFactory<'U,'V>, secondPipeIdx:PipeIdx) = - inherit SeqFactory<'T,'V>() - - override __.PipeIdx = - secondPipeIdx - - override this.Create<'W> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Consumer<'V,'W>) : Consumer<'T,'W> = - first.Create outOfBand pipeIdx (second.Create outOfBand secondPipeIdx next) - - static member Combine (first:SeqFactory<'T,'U>) (second:SeqFactory<'U,'V>) : SeqFactory<'T,'V> = - upcast ComposedFactory(first, second, first.PipeIdx+1) - - and IdentityFactory<'T> () = - inherit SeqFactory<'T,'T> () - static let singleton : SeqFactory<'T,'T> = upcast (IdentityFactory<'T>()) - override __.Create<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Consumer<'T,'V>) : Consumer<'T,'V> = next + let inline seq<'T,'seq when 'seq :> ISeq<'T> and 'seq : not struct> (t:'seq) : ISeq<'T> = (# "" t : ISeq<'T> #) + let inline enumerable<'T,'enumerable when 'enumerable :> IEnumerable<'T> and 'enumerable : not struct> (t:'enumerable) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #) + let inline enumerator<'T,'enumerator when 'enumerator :> IEnumerator<'T> and 'enumerator : not struct> (t:'enumerator) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #) + let inline enumeratorNonGeneric<'enumerator when 'enumerator :> IEnumerator and 'enumerator : not struct> (t:'enumerator) : IEnumerator = (# "" t : IEnumerator #) + let inline outOfBand<'outOfBand when 'outOfBand :> IOutOfBand and 'outOfBand : not struct> (t:'outOfBand) : IOutOfBand = (# "" t : IOutOfBand #) + + let createFold (factory:TransformFactory<_,_>) (folder:Folder<_,_,_>) pipeIdx = + factory.Compose (Upcast.outOfBand folder) pipeIdx folder + + let inline valueComparer<'T when 'T : equality> ()= + let c = HashIdentity.Structural<'T> + { new IEqualityComparer> with + member __.GetHashCode o = c.GetHashCode o._1 + member __.Equals (lhs,rhs) = c.Equals (lhs._1, rhs._1) } + + type ComposedFactory<'T,'U,'V> private (first:TransformFactory<'T,'U>, second:TransformFactory<'U,'V>) = + inherit TransformFactory<'T,'V>() + + override this.Compose<'W> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Activity<'V,'W>) : Activity<'T,'W> = + first.Compose outOfBand (pipeIdx-1) (second.Compose outOfBand pipeIdx next) + + static member Combine (first:TransformFactory<'T,'U>) (second:TransformFactory<'U,'V>) : TransformFactory<'T,'V> = + upcast ComposedFactory(first, second) + + and IdentityFactory<'T> private () = + inherit TransformFactory<'T,'T> () + static let singleton : TransformFactory<'T,'T> = upcast (IdentityFactory<'T>()) + override __.Compose<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Activity<'T,'V>) : Activity<'T,'V> = next static member Instance = singleton - and ISkipping = + and ISkipable = // Seq.init(Infinite)? lazily uses Current. The only Composer component that can do that is Skip // and it can only do it at the start of a sequence - abstract Skipping : unit -> bool + abstract CanSkip : unit -> bool type SeqProcessNextStates = | InProcess = 0 @@ -181,89 +183,135 @@ namespace Microsoft.FSharp.Collections | Finished = 2 type Result<'T>() = - let mutable haltedIdx = 0 + inherit Folder<'T,'T,NoValue>(Unchecked.defaultof<'T>,Unchecked.defaultof) - member val Current = Unchecked.defaultof<'T> with get, set member val SeqState = SeqProcessNextStates.NotStarted with get, set - member __.HaltedIdx = haltedIdx - interface IOutOfBand with - member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx - - // SetResult<> is used at the end of the chain of SeqComponents to assign the final value - type SetResult<'T> (result:Result<'T>) = - inherit Consumer<'T,'T>() - - override __.ProcessNext (input:'T) : bool = - result.Current <- input + override this.ProcessNext (input:'T) : bool = + this.Result <- input true - type OutOfBand() = - let mutable haltedIdx = 0 - interface IOutOfBand with member __.StopFurtherProcessing pipeIdx = haltedIdx <- pipeIdx - member __.HaltedIdx = haltedIdx - - module ForEach = - let enumerable (enumerable:IEnumerable<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - use enumerator = enumerable.GetEnumerator () - while (outOfBand.HaltedIdx = 0) && (enumerator.MoveNext ()) do - consumer.ProcessNext enumerator.Current |> ignore - - let array (array:array<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let mutable idx = 0 - while (outOfBand.HaltedIdx = 0) && (idx < array.Length) do - consumer.ProcessNext array.[idx] |> ignore - idx <- idx + 1 - - let list (alist:list<'T>) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let rec iterate lst = - match outOfBand.HaltedIdx, lst with - | 0, hd :: tl -> - consumer.ProcessNext hd |> ignore - iterate tl - | _ -> () - iterate alist - - let unfold (generator:'S->option<'T*'S>) state (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let rec iterate current = - match outOfBand.HaltedIdx, generator current with - | 0, Some (item, next) -> - consumer.ProcessNext item |> ignore - iterate next - | _ -> () - - iterate state - - let makeIsSkipping (consumer:Consumer<'T,'U>) = - match box consumer with - | :? ISkipping as skip -> skip.Skipping - | _ -> fun () -> false - - let init f (terminatingIdx:int) (outOfBand:OutOfBand) (consumer:Consumer<'T,'U>) = - let mutable idx = -1 - let isSkipping = makeIsSkipping consumer - let mutable maybeSkipping = true - while (outOfBand.HaltedIdx = 0) && (idx < terminatingIdx) do - if maybeSkipping then - maybeSkipping <- isSkipping () + module Fold = + type IIterate<'T> = + abstract Iterate<'U,'Result,'State> : outOfBand:Folder<'U,'Result,'State> -> consumer:Activity<'T,'U> -> unit + + [] + type enumerable<'T> (enumerable:IEnumerable<'T>) = + interface IIterate<'T> with + member __.Iterate (outOfBand:Folder<'U,'Result,'State>) (consumer:Activity<'T,'U>) = + use enumerator = enumerable.GetEnumerator () + let rec iterate () = + if enumerator.MoveNext () then + consumer.ProcessNext enumerator.Current |> ignore + if outOfBand.HaltedIdx = 0 then + iterate () + iterate () + + [] + type Array<'T> (array:array<'T>) = + interface IIterate<'T> with + member __.Iterate (outOfBand:Folder<'U,'Result,'State>) (consumer:Activity<'T,'U>) = + let array = array + let rec iterate idx = + if idx < array.Length then + consumer.ProcessNext array.[idx] |> ignore + if outOfBand.HaltedIdx = 0 then + iterate (idx+1) + iterate 0 + + [] + type resizeArray<'T> (array:ResizeArray<'T>) = + interface IIterate<'T> with + member __.Iterate (outOfBand:Folder<'U,'Result,'State>) (consumer:Activity<'T,'U>) = + let array = array + let rec iterate idx = + if idx < array.Count then + consumer.ProcessNext array.[idx] |> ignore + if outOfBand.HaltedIdx = 0 then + iterate (idx+1) + iterate 0 + + [] + type List<'T> (alist:list<'T>) = + interface IIterate<'T> with + member __.Iterate (outOfBand:Folder<'U,'Result,'State>) (consumer:Activity<'T,'U>) = + let rec iterate lst = + match lst with + | hd :: tl -> + consumer.ProcessNext hd |> ignore + if outOfBand.HaltedIdx = 0 then + iterate tl + | _ -> () + iterate alist + + [] + type unfold<'S,'T> (generator:'S->option<'T*'S>, state:'S) = + interface IIterate<'T> with + member __.Iterate (outOfBand:Folder<'U,'Result,'State>) (consumer:Activity<'T,'U>) = + let generator = generator + let rec iterate current = + match generator current with + | Some (item, next) -> + consumer.ProcessNext item |> ignore + if outOfBand.HaltedIdx = 0 then + iterate next + | _ -> () + iterate state + + [] + type init<'T> (f:int->'T, terminatingIdx:int) = + interface IIterate<'T> with + member __.Iterate (outOfBand:Folder<'U,'Result,'State>) (consumer:Activity<'T,'U>) = + let terminatingIdx = terminatingIdx + let f = f + + let firstIdx = + match box consumer with + | :? ISkipable as skipping -> + let rec skip idx = + if idx = terminatingIdx || outOfBand.HaltedIdx <> 0 then + terminatingIdx + elif skipping.CanSkip () then + skip (idx+1) + else + idx + skip -1 + | _ -> -1 + + let rec iterate idx = + if idx < terminatingIdx then + consumer.ProcessNext (f (idx+1)) |> ignore + if outOfBand.HaltedIdx = 0 then + iterate (idx+1) + else + idx + else + idx - if not maybeSkipping then - consumer.ProcessNext (f (idx+1)) |> ignore + let finalIdx = iterate firstIdx + if outOfBand.HaltedIdx = 0 && finalIdx = System.Int32.MaxValue then + raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) - idx <- idx + 1 + let execute (createFolder:PipeIdx->Folder<'U,'Result,'State>) (transformFactory:TransformFactory<'T,'U>) pipeIdx (executeOn:#IIterate<'T>) = + let mutable stopTailCall = () + let result = createFolder (pipeIdx+1) + let consumer = createFold transformFactory result pipeIdx + try + executeOn.Iterate result consumer + consumer.ChainComplete (&stopTailCall, result.HaltedIdx) + result.Result + finally + consumer.ChainDispose (&stopTailCall) - let execute (f:(unit->unit)->#Consumer<'U,'U>) (current:SeqFactory<'T,'U>) executeOn = - let pipeline = OutOfBand() - let result = f (fun () -> (pipeline:>IOutOfBand).StopFurtherProcessing (current.PipeIdx+1)) - let consumer = current.Build pipeline result + let executeThin (createFolder:PipeIdx->Folder<'T,'Result,'State>) (executeOn:#IIterate<'T>) = + let mutable stopTailCall = () + let result = createFolder 1 try - executeOn pipeline consumer - let mutable stopTailCall = () - (Upcast.iCompletionChain consumer).ChainComplete (&stopTailCall, pipeline.HaltedIdx) - result + executeOn.Iterate result result + result.ChainComplete (&stopTailCall, result.HaltedIdx) + result.Result finally - let mutable stopTailCall = () - (Upcast.iCompletionChain consumer).ChainDispose (&stopTailCall) + result.ChainDispose (&stopTailCall) module Enumerable = type Empty<'T>() = @@ -282,11 +330,11 @@ namespace Microsoft.FSharp.Collections static member Element = element [] - type EnumeratorBase<'T>(result:Result<'T>, seqComponent:ICompletionChain) = + type EnumeratorBase<'T>(result:Result<'T>, activity:Activity) = interface IDisposable with - member __.Dispose() : unit = + member __.Dispose () : unit = let mutable stopTailCall = () - seqComponent.ChainDispose (&stopTailCall) + activity.ChainDispose (&stopTailCall) interface IEnumerator with member this.Current : obj = box ((Upcast.enumerator this)).Current @@ -295,7 +343,7 @@ namespace Microsoft.FSharp.Collections interface IEnumerator<'T> with member __.Current = - if result.SeqState = SeqProcessNextStates.InProcess then result.Current + if result.SeqState = SeqProcessNextStates.InProcess then result.Result else match result.SeqState with | SeqProcessNextStates.NotStarted -> notStarted() @@ -306,9 +354,9 @@ namespace Microsoft.FSharp.Collections let derivedClassShouldImplement () = failwith "library implementation error: derived class should implement (should be abstract)" - abstract member Append : (seq<'T>) -> IEnumerable<'T> + abstract member Append : (ISeq<'T>) -> ISeq<'T> - default this.Append source = Upcast.enumerable (AppendEnumerable [this; source]) + default this.Append source = Upcast.seq (AppendEnumerable [this; source]) interface IEnumerable with member this.GetEnumerator () : IEnumerator = @@ -320,22 +368,22 @@ namespace Microsoft.FSharp.Collections member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement () interface ISeq<'T> with - member __.Compose _ = derivedClassShouldImplement () - member __.ForEach _ = derivedClassShouldImplement () + member __.PushTransform _ = derivedClassShouldImplement () + member __.Fold _ = derivedClassShouldImplement () - and Enumerator<'T,'U>(source:IEnumerator<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit EnumeratorBase<'U>(result, seqComponent) + and Enumerator<'T,'U>(source:IEnumerator<'T>, activity:Activity<'T,'U>, result:Result<'U>) = + inherit EnumeratorBase<'U>(result, activity) let rec moveNext () = if (result.HaltedIdx = 0) && source.MoveNext () then - if seqComponent.ProcessNext source.Current then + if activity.ProcessNext source.Current then true else moveNext () else result.SeqState <- SeqProcessNextStates.Finished let mutable stopTailCall = () - (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) + activity.ChainComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -344,27 +392,53 @@ namespace Microsoft.FSharp.Collections moveNext () interface IDisposable with - member __.Dispose() = + member __.Dispose () = try source.Dispose () finally let mutable stopTailCall = () - (Upcast.iCompletionChain seqComponent).ChainDispose (&stopTailCall) + activity.ChainDispose (&stopTailCall) - and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:SeqFactory<'T,'U>) = + and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:TransformFactory<'T,'U>, pipeIdx:PipeIdx) = inherit EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), current.Build result (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), createFold current result pipeIdx, result)) interface ISeq<'U> with - member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next)) + member __.PushTransform (next:TransformFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next, pipeIdx+1)) + + member this.Fold<'Result,'State> (f:PipeIdx->Folder<'U,'Result,'State>) = + Fold.execute f current pipeIdx (Fold.enumerable enumerable) + + and EnumerableThin<'T>(enumerable:IEnumerable<'T>) = + inherit EnumerableBase<'T>() + + interface IEnumerable<'T> with + member this.GetEnumerator () = enumerable.GetEnumerator () + + interface ISeq<'T> with + member __.PushTransform (next:TransformFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (new Enumerable<'T,'U>(enumerable, next, 1)) - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.enumerable enumerable) + member this.Fold<'Result,'State> (f:PipeIdx->Folder<'T,'Result,'State>) = + Fold.executeThin f (Fold.enumerable enumerable) + + and SeqDelayed<'T>(delayed:unit->ISeq<'T>, pipeIdx:PipeIdx) = + inherit EnumerableBase<'T>() + + interface IEnumerable<'T> with + member this.GetEnumerator () : IEnumerator<'T> = (delayed()).GetEnumerator () + + interface ISeq<'T> with + member __.PushTransform (next:TransformFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (new SeqDelayed<'U>((fun () -> (delayed()).PushTransform next), pipeIdx+1)) + + member this.Fold<'Result,'State> (f:PipeIdx->Folder<'T,'Result,'State>) = + (delayed()).Fold f and ConcatEnumerator<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = let mutable state = SeqProcessNextStates.NotStarted @@ -400,11 +474,11 @@ namespace Microsoft.FSharp.Collections member __.Reset () = noReset () interface IDisposable with - member __.Dispose() = + member __.Dispose () = main.Dispose () active.Dispose () - and AppendEnumerable<'T> (sources:list>) = + and AppendEnumerable<'T> (sources:list>) = inherit EnumerableBase<'T>() interface IEnumerable<'T> with @@ -412,14 +486,14 @@ namespace Microsoft.FSharp.Collections Upcast.enumerator (new ConcatEnumerator<_,_> (sources |> List.rev)) override this.Append source = - Upcast.enumerable (AppendEnumerable (source :: sources)) + Upcast.seq (AppendEnumerable (source::sources)) interface ISeq<'T> with - member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = - Upcast.seq (Enumerable<'T,'V>(this, next)) + member this.PushTransform (next:TransformFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable<'T,'V>(this, next, 1)) - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) + member this.Fold<'Result,'State> (f:PipeIdx->Folder<'T,'Result,'State>) = + Fold.executeThin f (Fold.enumerable this) and ConcatEnumerable<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) = inherit EnumerableBase<'T>() @@ -429,14 +503,14 @@ namespace Microsoft.FSharp.Collections Upcast.enumerator (new ConcatEnumerator<_,_> (sources)) interface ISeq<'T> with - member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = - Upcast.seq (Enumerable<'T,'V>(this, next)) + member this.PushTransform (next:TransformFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable<'T,'V>(this, next, 1)) - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) + member this.Fold<'Result,'State> (f:PipeIdx->Folder<'T,'Result,'State>) = + Fold.executeThin f (Fold.enumerable this) let create enumerable current = - Upcast.seq (Enumerable(enumerable, current)) + Upcast.seq (Enumerable (enumerable, current, 1)) module EmptyEnumerable = type Enumerable<'T> () = @@ -449,87 +523,103 @@ namespace Microsoft.FSharp.Collections member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>() override this.Append source = - Upcast.enumerable (Enumerable.Enumerable<'T,'T> (source, IdentityFactory.Instance)) + Upcast.seq (Enumerable.EnumerableThin<'T> source) interface ISeq<'T> with - member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = - Upcast.seq (Enumerable.Enumerable<'T,'V>(this, next)) - - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable this) - + member this.PushTransform (next:TransformFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable.Enumerable<'T,'V>(this, next, 1)) + member this.Fold<'Result,'State> (f:PipeIdx->Folder<'T,'Result,'State>) = + Fold.executeThin f (Fold.enumerable this) module Array = - type Enumerator<'T,'U>(delayedArray:unit->array<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + type Enumerator<'T,'U>(array:array<'T>, activity:Activity<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, activity) let mutable idx = 0 - let mutable array = Unchecked.defaultof<_> - - let mutable initMoveNext = Unchecked.defaultof<_> - do - initMoveNext <- - fun () -> - result.SeqState <- SeqProcessNextStates.InProcess - array <- delayedArray () - initMoveNext <- ignore let rec moveNext () = if (result.HaltedIdx = 0) && idx < array.Length then idx <- idx+1 - if seqComponent.ProcessNext array.[idx-1] then + if activity.ProcessNext array.[idx-1] then true else moveNext () else result.SeqState <- SeqProcessNextStates.Finished let mutable stopTailCall = () - (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) + activity.ChainComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with member __.MoveNext () = - initMoveNext () + result.SeqState <- SeqProcessNextStates.InProcess moveNext () - type Enumerable<'T,'U>(delayedArray:unit->array<'T>, current:SeqFactory<'T,'U>) = + type Enumerable<'T,'U>(array:array<'T>, transformFactory:TransformFactory<'T,'U>, pipeIdx:PipeIdx) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U>(delayedArray, current.Build result (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U>(array, createFold transformFactory result pipeIdx, result)) interface ISeq<'U> with - member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V>(delayedArray, ComposedFactory.Combine current next)) + member __.PushTransform (next:TransformFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(array, ComposedFactory.Combine transformFactory next, 1)) + + member this.Fold<'Result,'State> (f:PipeIdx->Folder<'U,'Result,'State>) = + Fold.execute f transformFactory pipeIdx (Fold.Array array) + + module ResizeArray = + type Enumerator<'T,'U>(array:ResizeArray<'T>, activity:Activity<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, activity) + + let mutable idx = 0 + + let rec moveNext () = + if (result.HaltedIdx = 0) && idx < array.Count then + idx <- idx+1 + if activity.ProcessNext array.[idx-1] then + true + else + moveNext () + else + result.SeqState <- SeqProcessNextStates.Finished + let mutable stopTailCall = () + activity.ChainComplete (&stopTailCall, result.HaltedIdx) + false - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.array (delayedArray ())) + interface IEnumerator with + member __.MoveNext () = + result.SeqState <- SeqProcessNextStates.InProcess + moveNext () - let createDelayed (delayedArray:unit->array<'T>) (current:SeqFactory<'T,'U>) = - Upcast.seq (Enumerable(delayedArray, current)) + type Enumerable<'T,'U>(resizeArray:ResizeArray<'T>, transformFactory:TransformFactory<'T,'U>, pipeIdx:PipeIdx) = + inherit Enumerable.EnumerableBase<'U>() - let create (array:array<'T>) (current:SeqFactory<'T,'U>) = - createDelayed (fun () -> array) current + interface IEnumerable<'U> with + member this.GetEnumerator () : IEnumerator<'U> = + let result = Result<'U> () + Upcast.enumerator (new Enumerator<'T,'U>(resizeArray, createFold transformFactory result pipeIdx, result)) - let createDelayedId (delayedArray:unit -> array<'T>) = - createDelayed delayedArray IdentityFactory.Instance + interface ISeq<'U> with + member __.PushTransform (next:TransformFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(resizeArray, ComposedFactory.Combine transformFactory next, 1)) - let createId (array:array<'T>) = - create array IdentityFactory.Instance + member this.Fold<'Result,'State> (f:PipeIdx->Folder<'U,'Result,'State>) = + Fold.execute f transformFactory pipeIdx (Fold.resizeArray resizeArray) module List = - type Enumerator<'T,'U>(alist:list<'T>, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + type Enumerator<'T,'U>(alist:list<'T>, activity:Activity<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, activity) let mutable list = alist let rec moveNext current = match result.HaltedIdx, current with | 0, head::tail -> - if seqComponent.ProcessNext head then + if activity.ProcessNext head then list <- tail true else @@ -537,7 +627,7 @@ namespace Microsoft.FSharp.Collections | _ -> result.SeqState <- SeqProcessNextStates.Finished let mutable stopTailCall = () - (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) + activity.ChainComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -545,27 +635,27 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext list - type Enumerable<'T,'U>(alist:list<'T>, current:SeqFactory<'T,'U>) = + type Enumerable<'T,'U>(alist:list<'T>, transformFactory:TransformFactory<'T,'U>, pipeIdx:PipeIdx) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U>(alist, current.Build result (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U>(alist, createFold transformFactory result pipeIdx, result)) interface ISeq<'U> with - member __.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine current next)) + member __.PushTransform (next:TransformFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine transformFactory next, pipeIdx+1)) - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.list alist) + member this.Fold<'Result,'State> (f:PipeIdx->Folder<'U,'Result,'State>) = + Fold.execute f transformFactory pipeIdx (Fold.List alist) let create alist current = - Upcast.seq (Enumerable(alist, current)) + Upcast.seq (Enumerable(alist, current, 1)) module Unfold = - type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, activity:Activity<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, activity) let mutable current = state @@ -573,7 +663,7 @@ namespace Microsoft.FSharp.Collections match result.HaltedIdx, generator current with | 0, Some (item, nextState) -> current <- nextState - if seqComponent.ProcessNext item then + if activity.ProcessNext item then true else moveNext () @@ -584,20 +674,20 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext () - type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, current:SeqFactory<'T,'U>) = + type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, transformFactory:TransformFactory<'T,'U>, pipeIdx:PipeIdx) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, current.Build result (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, createFold transformFactory result pipeIdx, result)) interface ISeq<'U> with - member this.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine current next)) + member this.PushTransform (next:TransformFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine transformFactory next, pipeIdx+1)) - member this.ForEach (f:(unit->unit)->#Consumer<'U,'U>) = - ForEach.execute f current (ForEach.unfold generator state) + member this.Fold<'Result,'State> (f:PipeIdx->Folder<'U,'Result,'State>) = + Fold.execute f transformFactory pipeIdx (Fold.unfold (generator, state)) module Init = // The original implementation of "init" delayed the calculation of Current, and so it was possible @@ -619,11 +709,13 @@ namespace Microsoft.FSharp.Collections else System.Int32.MaxValue - type Enumerator<'T,'U>(count:Nullable, f:int->'T, seqComponent:Consumer<'T,'U>, result:Result<'U>) = - inherit Enumerable.EnumeratorBase<'U>(result, seqComponent) + type Enumerator<'T,'U>(count:Nullable, f:int->'T, activity:Activity<'T,'U>, result:Result<'U>) = + inherit Enumerable.EnumeratorBase<'U>(result, activity) let isSkipping = - ForEach.makeIsSkipping seqComponent + match box activity with + | :? ISkipable as skip -> skip.CanSkip + | _ -> fun () -> false let terminatingIdx = getTerminatingIdx count @@ -632,7 +724,7 @@ namespace Microsoft.FSharp.Collections let mutable idx = -1 let rec moveNext () = - if (result.HaltedIdx = 0) && idx < terminatingIdx then + if result.HaltedIdx = 0 && idx < terminatingIdx then idx <- idx + 1 if maybeSkipping then @@ -642,16 +734,16 @@ namespace Microsoft.FSharp.Collections if maybeSkipping then moveNext () - elif seqComponent.ProcessNext (f idx) then + elif activity.ProcessNext (f idx) then true else moveNext () - elif (result.HaltedIdx = 0) && idx = System.Int32.MaxValue then + elif result.HaltedIdx = 0 && idx = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue)) else result.SeqState <- SeqProcessNextStates.Finished let mutable stopTailCall = () - (Upcast.iCompletionChain seqComponent).ChainComplete (&stopTailCall, result.HaltedIdx) + activity.ChainComplete (&stopTailCall, result.HaltedIdx) false interface IEnumerator with @@ -659,21 +751,21 @@ namespace Microsoft.FSharp.Collections result.SeqState <- SeqProcessNextStates.InProcess moveNext () - type Enumerable<'T,'U>(count:Nullable, f:int->'T, current:SeqFactory<'T,'U>) = + type Enumerable<'T,'U>(count:Nullable, f:int->'T, transformFactory:TransformFactory<'T,'U>, pipeIdx:PipeIdx) = inherit Enumerable.EnumerableBase<'U>() interface IEnumerable<'U> with member this.GetEnumerator () : IEnumerator<'U> = let result = Result<'U> () - Upcast.enumerator (new Enumerator<'T,'U>(count, f, current.Build result (SetResult<'U> result), result)) + Upcast.enumerator (new Enumerator<'T,'U>(count, f, createFold transformFactory result pipeIdx, result)) interface ISeq<'U> with - member this.Compose (next:SeqFactory<'U,'V>) : ISeq<'V> = - Upcast.seq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine current next)) + member this.PushTransform (next:TransformFactory<'U,'V>) : ISeq<'V> = + Upcast.seq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine transformFactory next, pipeIdx+1)) - member this.ForEach (createResult:(unit->unit)->#Consumer<'U,'U>) = + member this.Fold<'Result,'State> (createResult:PipeIdx->Folder<'U,'Result,'State>) = let terminatingIdx = getTerminatingIdx count - ForEach.execute createResult current (ForEach.init f terminatingIdx) + Fold.execute createResult transformFactory pipeIdx (Fold.init (f, terminatingIdx)) let upto lastOption f = match lastOption with @@ -721,11 +813,11 @@ namespace Microsoft.FSharp.Collections setIndex (!index + 1) true ) - member self.Reset() = noReset() + member this.Reset() = noReset() interface System.IDisposable with - member x.Dispose() = () } + member x.Dispose () = () } - type EnumerableDecider<'T>(count:Nullable, f:int->'T) = + type EnumerableDecider<'T>(count:Nullable, f:int->'T, pipeIdx:PipeIdx) = inherit Enumerable.EnumerableBase<'T>() interface IEnumerable<'T> with @@ -736,835 +828,861 @@ namespace Microsoft.FSharp.Collections upto (if count.HasValue then Some (count.Value-1) else None) f interface ISeq<'T> with - member this.Compose (next:SeqFactory<'T,'U>) : ISeq<'U> = - Upcast.seq (Enumerable<'T,'V>(count, f, next)) + member this.PushTransform (next:TransformFactory<'T,'U>) : ISeq<'U> = + Upcast.seq (Enumerable<'T,'V>(count, f, next, pipeIdx+1)) - member this.ForEach (f:(unit->unit)->#Consumer<'T,'T>) = - ForEach.execute f IdentityFactory.Instance (ForEach.enumerable (Upcast.enumerable this)) + member this.Fold<'Result,'State> (f:PipeIdx->Folder<'T,'Result,'State>) = + Fold.executeThin f (Fold.enumerable (Upcast.enumerable this)) + [] + let ofResizeArrayUnchecked (source:ResizeArray<'T>) : ISeq<'T> = + Upcast.seq (ResizeArray.Enumerable (source, IdentityFactory.Instance, 1)) - [] - let toComposer (source:seq<'T>) : ISeq<'T> = - match source with - | :? ISeq<'T> as s -> s - | :? array<'T> as a -> Upcast.seq (Array.Enumerable((fun () -> a), IdentityFactory.Instance)) - | :? list<'T> as a -> Upcast.seq (List.Enumerable(a, IdentityFactory.Instance)) - | null -> nullArg "source" - | _ -> Upcast.seq (Enumerable.Enumerable<'T,'T>(source, IdentityFactory.Instance)) + [] + let ofArray (source:array<'T>) : ISeq<'T> = + Upcast.seq (Array.Enumerable (source, IdentityFactory.Instance, 1)) + [] + let ofList (source:list<'T>) : ISeq<'T> = + Upcast.seq (List.Enumerable (source, IdentityFactory.Instance, 1)) - let inline foreach f (source:ISeq<_>) = source.ForEach f - let inline compose (factory:#SeqFactory<_,_>) (source:ISeq<'T>) = source.Compose factory + [] + let ofSeq (source:seq<'T>) : ISeq<'T> = + match source with + | :? ISeq<'T> as seq -> seq + | :? array<'T> as array -> ofArray array + | :? list<'T> as list -> ofList list + | null -> nullArg "source" + | _ -> Upcast.seq (Enumerable.EnumerableThin<'T> source) [] - let inline average (source: ISeq< ^T>) : ^T - when ^T:(static member Zero : ^T) - and ^T:(static member (+) : ^T * ^T -> ^T) - and ^T:(static member DivideByInt : ^T * int -> ^T) = - source - |> foreach (fun _ -> - { new FolderWithOnComplete< ^T, Values< ^T, int>> (Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + let inline average (source:ISeq<'T>) = + source.Fold (fun _ -> + upcast { new FolderWithPostProcessing<'T,'T,int> (LanguagePrimitives.GenericZero, 0) with override this.ProcessNext value = - this.Value._1 <- Checked.(+) this.Value._1 value - this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + this.Result <- Checked.(+) this.Result value + this.State <- this.State + 1 + Unchecked.defaultof<_> (* return value unused in Fold context *) override this.OnComplete _ = - if this.Value._2 = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) - |> fun total -> LanguagePrimitives.DivideByInt< ^T> total.Value._1 total.Value._2 - + if this.State = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + this.Result <- LanguagePrimitives.DivideByInt<'T> this.Result this.State + override this.OnDispose () = () }) [] - let inline averageBy (f : 'T -> ^U) (source: ISeq< 'T >) : ^U - when ^U:(static member Zero : ^U) - and ^U:(static member (+) : ^U * ^U -> ^U) - and ^U:(static member DivideByInt : ^U * int -> ^U) = - source - |> foreach (fun _ -> - { new FolderWithOnComplete<'T,Values<'U, int>>(Values<_,_>(LanguagePrimitives.GenericZero, 0)) with + let inline averageBy (f:'T->'U) (source:ISeq<'T>) = + source.Fold (fun _ -> + upcast { new FolderWithPostProcessing<'T,'U,int>(LanguagePrimitives.GenericZero,0) with override this.ProcessNext value = - this.Value._1 <- Checked.(+) this.Value._1 (f value) - this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + this.Result <- Checked.(+) this.Result (f value) + this.State <- this.State + 1 + Unchecked.defaultof<_> (* return value unused in Fold context *) override this.OnComplete _ = - if this.Value._2 = 0 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString }) - |> fun total -> LanguagePrimitives.DivideByInt< ^U> total.Value._1 total.Value._2 - + if this.State = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + this.Result <- LanguagePrimitives.DivideByInt<'U> this.Result this.State + override this.OnDispose () = () }) [] let empty<'T> = EmptyEnumerable.Enumerable<'T>.Instance - [] - let inline exactlyOne errorString (source : ISeq<'T>) : 'T = - source - |> foreach (fun halt -> - { new FolderWithOnComplete<'T, Values>(Values(true, Unchecked.defaultof<'T>, false)) with + let exactlyOne (source:ISeq<'T>) : 'T = + source.Fold (fun pipeIdx -> + upcast { new FolderWithPostProcessing<'T,'T,Values>(Unchecked.defaultof<'T>, Values(true, false)) with override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value + if this.State._1 then + this.State._1 <- false + this.Result <- value else - this.Value._3 <- true - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + this.State._2 <- true + this.StopFurtherProcessing pipeIdx + Unchecked.defaultof<_> (* return value unused in Fold context *) override this.OnComplete _ = - if this.Value._1 then + if this.State._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - elif this.Value._3 then - invalidArg "source" errorString }) - |> fun one -> one.Value._2 - + elif this.State._2 then + invalidArg "source" (SR.GetString SR.inputSequenceTooLong) + override this.OnDispose () = () }) [] let inline fold<'T,'State> (f:'State->'T->'State) (seed:'State) (source:ISeq<'T>) : 'State = - source - |> foreach (fun _ -> - { new Folder<'T,'State>(seed) with + source.Fold (fun _ -> + upcast { new Folder<'T,'State,NoValue>(seed,Unchecked.defaultof) with override this.ProcessNext value = - this.Value <- f this.Value value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - }) - |> fun folded -> folded.Value - + this.Result <- f this.Result value + Unchecked.defaultof<_> (* return value unused in Fold context *) }) [] - let inline fold2<'T1,'T2,'State> (folder:'State->'T1->'T2->'State) (state:'State) (source1: ISeq<'T1>) (source2: ISeq<'T2>) = - source1 - |> foreach (fun halt -> - { new FolderWithOnComplete<_,Values<'State,IEnumerator<'T2>>>(Values<_,_>(state,source2.GetEnumerator())) with - override self.ProcessNext value = - if self.Value._2.MoveNext() then - self.Value._1 <- folder self.Value._1 value self.Value._2.Current + let inline fold2<'T1,'T2,'State> (folder:'State->'T1->'T2->'State) (state:'State) (source1:ISeq<'T1>) (source2: ISeq<'T2>) = + source1.Fold (fun pipeIdx -> + upcast { new FolderWithPostProcessing<_,'State,IEnumerator<'T2>>(state,source2.GetEnumerator()) with + override this.ProcessNext value = + if this.State.MoveNext() then + this.Result <- folder this.Result value this.State.Current else - halt() - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - - override self.OnComplete _ = - self.Value._2.Dispose() - }) - |> fun fold -> fold.Value._1 + this.StopFurtherProcessing pipeIdx + Unchecked.defaultof<_> (* return value unused in Fold context *) + override this.OnComplete _ = () + override this.OnDispose () = this.State.Dispose () }) [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> = - Upcast.seq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance)) - + Upcast.seq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance, 1)) [] let initInfinite<'T> (f:int->'T) : ISeq<'T> = - Upcast.seq (new Init.EnumerableDecider<'T>(Nullable (), f)) - + Upcast.seq (new Init.EnumerableDecider<'T>(Nullable (), f, 1)) [] let init<'T> (count:int) (f:int->'T) : ISeq<'T> = if count < 0 then invalidArgInputMustBeNonNegative "count" count elif count = 0 then empty else - Upcast.seq (new Init.EnumerableDecider<'T>(Nullable count, f)) - + Upcast.seq (new Init.EnumerableDecider<'T>(Nullable count, f, 1)) [] - let iter f (source:ISeq<'T>) = - source - |> foreach (fun _ -> - { new Consumer<'T,'T> () with + let inline iter f (source:ISeq<'T>) = + source.Fold (fun _ -> + upcast { new Folder<'T,unit,NoValue> ((),Unchecked.defaultof) with override this.ProcessNext value = f value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> ignore - + Unchecked.defaultof<_> (* return value unused in Fold context *) }) [] let inline iter2 (f:'T->'U->unit) (source1:ISeq<'T>) (source2:ISeq<'U>) : unit = - source1 - |> foreach (fun halt -> - { new FolderWithOnComplete<'T,IEnumerator<'U>> (source2.GetEnumerator()) with - override self.ProcessNext value = - if self.Value.MoveNext() then - f value self.Value.Current + source1.Fold (fun pipeIdx -> + upcast { new FolderWithPostProcessing<'T,unit,IEnumerator<'U>> ((),source2.GetEnumerator()) with + override this.ProcessNext value = + if this.State.MoveNext() then + f value this.State.Current else - halt() - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - - override self.OnComplete _ = - self.Value.Dispose() - }) - |> ignore + this.StopFurtherProcessing pipeIdx + Unchecked.defaultof<_> (* return value unused in Fold context *) + override this.OnComplete _ = () + override this.OnDispose () = this.State.Dispose () }) [] - let inline iteri2 (f:int->'T->'U->unit) (source1:ISeq<'T>) (source2:seq<'U>) : unit = - source1 - |> foreach (fun halt -> - { new FolderWithOnComplete<'T,Values>>(Values<_,_>(-1,source2.GetEnumerator())) with - override self.ProcessNext value = - if self.Value._2.MoveNext() then - f self.Value._1 value self.Value._2.Current - self.Value._1 <- self.Value._1 + 1 + let inline iteri2 (f:int->'T->'U->unit) (source1:ISeq<'T>) (source2:ISeq<'U>) : unit = + source1.Fold (fun pipeIdx -> + upcast { new FolderWithPostProcessing<'T,unit,Values>>((),Values<_,_>(-1,source2.GetEnumerator())) with + override this.ProcessNext value = + if this.State._2.MoveNext() then + f this.State._1 value this.State._2.Current + this.State._1 <- this.State._1 + 1 Unchecked.defaultof<_> else - halt() + this.StopFurtherProcessing pipeIdx Unchecked.defaultof<_> - - override self.OnComplete _ = - self.Value._2.Dispose() - - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> ignore - + override this.OnComplete _ = () + override this.OnDispose () = this.State._2.Dispose () }) [] let tryHead (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, Option<'T>> (None) with + source.Fold (fun pipeIdx -> + upcast { new Folder<'T, Option<'T>,NoValue> (None,Unchecked.defaultof) with override this.ProcessNext value = - this.Value <- Some value - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun head -> head.Value + this.Result <- Some value + this.StopFurtherProcessing pipeIdx + Unchecked.defaultof<_> (* return value unused in Fold context *) }) + [] + let head (source:ISeq<_>) = + match tryHead source with + | None -> invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + | Some x -> x [] - let iteri f (source:ISeq<'T>) = - source - |> foreach (fun _ -> - { new Folder<'T, int> (0) with + let inline iteri f (source:ISeq<'T>) = + source.Fold (fun _ -> + { new Folder<'T,unit,int> ((),0) with override this.ProcessNext value = - f this.Value value - this.Value <- this.Value + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> ignore + f this.State value + this.State <- this.State + 1 + Unchecked.defaultof<_> (* return value unused in Fold context *) }) [] let inline except (itemsToExclude: seq<'T>) (source:ISeq<'T>) : ISeq<'T> when 'T:equality = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,Lazy>> - (Upcast.iCompletionChain next,lazy(HashSet<'T>(itemsToExclude,HashIdentity.Structural<'T>))) with + source.PushTransform { new TransformFactory<'T,'T>() with + override __.Compose _ _ next = + upcast { new Transform<'T,'V,Lazy>>(next,lazy(HashSet<'T>(itemsToExclude,HashIdentity.Structural<'T>))) with override this.ProcessNext (input:'T) : bool = - if this.Value.Value.Add input then TailCall.avoid (next.ProcessNext input) - else false - }} - + this.State.Value.Add input && TailCall.avoid (next.ProcessNext input) }} [] - let exists f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, bool> (false) with + let inline exists f (source:ISeq<'T>) = + source.Fold (fun pipeIdx -> + upcast { new Folder<'T, bool,NoValue> (false,Unchecked.defaultof) with override this.ProcessNext value = if f value then - this.Value <- true - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun exists -> exists.Value - + this.Result <- true + this.StopFurtherProcessing pipeIdx + Unchecked.defaultof<_> (* return value unused in Fold context *) }) [] - let exists2 (predicate:'T->'U->bool) (source1: ISeq<'T>) (source2: ISeq<'U>) : bool = - source1 - |> foreach (fun halt -> - { new FolderWithOnComplete<'T,Values>>(Values<_,_>(false,source2.GetEnumerator())) with - override self.ProcessNext value = - if self.Value._2.MoveNext() then - if predicate value self.Value._2.Current then - self.Value._1 <- true - halt() + let inline exists2 (predicate:'T->'U->bool) (source1:ISeq<'T>) (source2: ISeq<'U>) : bool = + source1.Fold (fun pipeIdx -> + upcast { new FolderWithPostProcessing<'T,bool,IEnumerator<'U>>(false,source2.GetEnumerator()) with + override this.ProcessNext value = + if this.State.MoveNext() then + if predicate value this.State.Current then + this.Result <- true + this.StopFurtherProcessing pipeIdx else - halt() - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - - override self.OnComplete _ = - self.Value._2.Dispose() - - }) - |> fun exists -> exists.Value._1 + this.StopFurtherProcessing pipeIdx + Unchecked.defaultof<_> (* return value unused in Fold context *) + override this.OnComplete _ = () + override this.OnDispose () = this.State.Dispose () }) [] let inline contains element (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, bool> (false) with + source.Fold (fun pipeIdx -> + upcast { new Folder<'T, bool,NoValue> (false,Unchecked.defaultof) with override this.ProcessNext value = if element = value then - this.Value <- true - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun contains -> contains.Value - + this.Result <- true + this.StopFurtherProcessing pipeIdx + Unchecked.defaultof<_> (* return value unused in Fold context *) }) [] - let forall predicate (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, bool> (true) with + let inline forall predicate (source:ISeq<'T>) = + source.Fold (fun pipeIdx -> + upcast { new Folder<'T, bool,NoValue> (true,Unchecked.defaultof) with override this.ProcessNext value = if not (predicate value) then - this.Value <- false - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun forall -> forall.Value - + this.Result <- false + this.StopFurtherProcessing pipeIdx + Unchecked.defaultof<_> (* return value unused in Fold context *) }) [] let inline forall2 predicate (source1:ISeq<'T>) (source2:ISeq<'U>) : bool = - source1 - |> foreach (fun halt -> - { new FolderWithOnComplete<'T,Values>>(Values<_,_>(true,source2.GetEnumerator())) with - override self.ProcessNext value = - if self.Value._2.MoveNext() then - if not (predicate value self.Value._2.Current) then - self.Value._1 <- false - halt() + source1.Fold (fun pipeIdx -> + upcast { new FolderWithPostProcessing<'T,bool,IEnumerator<'U>>(true,source2.GetEnumerator()) with + override this.ProcessNext value = + if this.State.MoveNext() then + if not (predicate value this.State.Current) then + this.Result <- false + this.StopFurtherProcessing pipeIdx else - halt() - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - - override self.OnComplete _ = - self.Value._2.Dispose() - }) - |> fun all -> all.Value._1 + this.StopFurtherProcessing pipeIdx + Unchecked.defaultof<_> (* return value unused in Fold context *) + override this.OnComplete _ = () + override this.OnDispose () = this.State.Dispose () }) [] let inline filter<'T> (f:'T->bool) (source:ISeq<'T>) : ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with - member __.ProcessNext input = + source.PushTransform { new TransformFactory<'T,'T>() with + override __.Compose _ _ next = + upcast { new Transform<'T,'V,NoValue>(next,Unchecked.defaultof) with + override __.ProcessNext input = if f input then TailCall.avoid (next.ProcessNext input) else false } } - [] let inline map<'T,'U> (f:'T->'U) (source:ISeq<'T>) : ISeq<'U> = - source |> compose { new SeqFactory<'T,'U>() with - member __.Create _ _ next = - upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with - member __.ProcessNext input = + source.PushTransform { new TransformFactory<'T,'U>() with + override __.Compose _ _ next = + upcast { new Transform<'T,'V,NoValue>(next,Unchecked.defaultof) with + override __.ProcessNext input = TailCall.avoid (next.ProcessNext (f input)) } } - [] - let inline mapi f source = - source |> compose { new SeqFactory<'T,'U>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,int>(Upcast.iCompletionChain next, -1) with + let inline mapi f (source:ISeq<_>) = + source.PushTransform { new TransformFactory<'T,'U>() with + override __.Compose _ _ next = + upcast { new Transform<'T,'V,int>(next, -1) with override this.ProcessNext (input:'T) : bool = - this.Value <- this.Value + 1 - TailCall.avoid (next.ProcessNext (f this.Value input)) } } - + this.State <- this.State + 1 + TailCall.avoid (next.ProcessNext (f this.State input)) } } [] - let inline map2<'First,'Second,'U> (map:'First->'Second->'U) (source1:ISeq<'First>) (source2:ISeq<'Second>) : ISeq<'U> = - source1 |> compose { new SeqFactory<'First,'U>() with - member __.Create<'V> outOfBand pipeIdx next = - upcast { new ConsumerChainedWithStateAndCleanup<'First,'V, IEnumerator<'Second>>(Upcast.iCompletionChain next, (source2.GetEnumerator ())) with - member self.ProcessNext input = - if self.Value.MoveNext () then - TailCall.avoid (next.ProcessNext (map input self.Value.Current)) + let inline map2<'T,'U,'V> (map:'T->'U->'V) (source1:ISeq<'T>) (source2:ISeq<'U>) : ISeq<'V> = + source1.PushTransform { new TransformFactory<'T,'V>() with + override __.Compose outOfBand pipeIdx (next:Activity<'V,'W>) = + upcast { new TransformWithPostProcessing<'T,'W, IEnumerator<'U>>(next, (source2.GetEnumerator ())) with + override this.ProcessNext input = + if this.State.MoveNext () then + TailCall.avoid (next.ProcessNext (map input this.State.Current)) else outOfBand.StopFurtherProcessing pipeIdx false - - override self.OnDispose () = () - override self.OnComplete _ = - self.Value.Dispose () } } - + override this.OnComplete _ = () + override this.OnDispose () = this.State.Dispose () }} [] - let inline mapi2<'First,'Second,'U> (map:int -> 'First->'Second->'U) (source1:ISeq<'First>) (source2:ISeq<'Second>) : ISeq<'U> = - source1 |> compose { new SeqFactory<'First,'U>() with - member __.Create<'V> outOfBand pipeIdx next = - upcast { new ConsumerChainedWithStateAndCleanup<'First,'V, Values>> - (Upcast.iCompletionChain next, Values<_,_>(-1, source2.GetEnumerator ())) with - member self.ProcessNext input = - if self.Value._2.MoveNext () then - self.Value._1 <- self.Value._1 + 1 - TailCall.avoid (next.ProcessNext (map self.Value._1 input self.Value._2.Current)) + let inline mapi2<'T,'U,'V> (map:int->'T->'U->'V) (source1:ISeq<'T>) (source2:ISeq<'U>) : ISeq<'V> = + source1.PushTransform { new TransformFactory<'T,'V>() with + override __.Compose<'W> outOfBand pipeIdx next = + upcast { new TransformWithPostProcessing<'T,'W, Values>>(next, Values<_,_>(-1,source2.GetEnumerator ())) with + override this.ProcessNext t = + let idx : byref<_> = &this.State._1 + let u = this.State._2 + if u.MoveNext () then + idx <- idx + 1 + TailCall.avoid (next.ProcessNext (map idx t u.Current)) else outOfBand.StopFurtherProcessing pipeIdx false - - override self.OnDispose () = () - override self.OnComplete _ = - self.Value._2.Dispose () } } - + override this.OnDispose () = this.State._2.Dispose () + override this.OnComplete _ = () }} [] - let inline map3<'First,'Second,'Third,'U> - (map:'First->'Second->'Third->'U) (source1:ISeq<'First>) (source2:ISeq<'Second>) (source3:ISeq<'Third>) : ISeq<'U> = - source1 |> compose { new SeqFactory<'First,'U>() with - member __.Create<'V> outOfBand pipeIdx next = - upcast { new ConsumerChainedWithStateAndCleanup<'First,'V, Values,IEnumerator<'Third>>> - (Upcast.iCompletionChain next, Values<_,_>(source2.GetEnumerator(),source3.GetEnumerator())) with - member self.ProcessNext input = - if self.Value._1.MoveNext() && self.Value._2.MoveNext () then - TailCall.avoid (next.ProcessNext (map input self.Value._1 .Current self.Value._2.Current)) + let inline map3<'T,'U,'V,'W>(map:'T->'U->'V->'W) (source1:ISeq<'T>) (source2:ISeq<'U>) (source3:ISeq<'V>) : ISeq<'W> = + source1.PushTransform { new TransformFactory<'T,'W>() with + override __.Compose<'X> outOfBand pipeIdx next = + upcast { new TransformWithPostProcessing<'T,'X,Values,IEnumerator<'V>>>(next,Values<_,_>(source2.GetEnumerator(),source3.GetEnumerator())) with + override this.ProcessNext t = + let u = this.State._1 + let v = this.State._2 + if u.MoveNext() && v.MoveNext () then + TailCall.avoid (next.ProcessNext (map t u.Current v.Current)) else outOfBand.StopFurtherProcessing pipeIdx false - - override self.OnDispose () = () - override self.OnComplete _ = - self.Value._1.Dispose () - self.Value._2.Dispose () } } - + override this.OnComplete _ = () + override this.OnDispose () = + this.State._1.Dispose () + this.State._2.Dispose () }} [] - let inline compareWith (f:'T -> 'T -> int) (source1 :ISeq<'T>) (source2:ISeq<'T>) : int = - source1 - |> foreach (fun halt -> - { new FolderWithOnComplete<'T,Values>>(Values<_,_>(0,source2.GetEnumerator())) with - override self.ProcessNext value = - if not (self.Value._2.MoveNext()) then - self.Value._1 <- 1 - halt () + let inline compareWith (f:'T->'T->int) (source1:ISeq<'T>) (source2:ISeq<'T>) : int = + source1.Fold (fun pipeIdx -> + upcast { new FolderWithPostProcessing<'T,int,IEnumerator<'T>>(0,source2.GetEnumerator()) with + override this.ProcessNext value = + if not (this.State.MoveNext()) then + this.Result <- 1 + this.StopFurtherProcessing pipeIdx else - let c = f value self.Value._2.Current + let c = f value this.State.Current if c <> 0 then - self.Value._1 <- c - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) - - override self.OnComplete _ = - if self.Value._1 = 0 && self.Value._2.MoveNext() then - self.Value._1 <- -1 - self.Value._2.Dispose() - }) - |> fun compare -> compare.Value._1 + this.Result <- c + this.StopFurtherProcessing pipeIdx + Unchecked.defaultof<_> (* return value unused in Fold context *) + override this.OnComplete _ = + if this.Result = 0 && this.State.MoveNext() then + this.Result <- -1 + override this.OnDispose () = this.State.Dispose () }) [] let inline choose (f:'T->option<'U>) (source:ISeq<'T>) : ISeq<'U> = - source |> compose { new SeqFactory<'T,'U>() with - member __.Create _ _ next = - upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with - member __.ProcessNext input = + source.PushTransform { new TransformFactory<'T,'U>() with + override __.Compose _ _ next = + upcast { new Transform<'T,'V,NoValue>(next,Unchecked.defaultof) with + override __.ProcessNext input = match f input with | Some value -> TailCall.avoid (next.ProcessNext value) | None -> false } } - [] let inline distinct (source:ISeq<'T>) : ISeq<'T> when 'T:equality = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,HashSet<'T>> - (Upcast.iCompletionChain next,(HashSet<'T>(HashIdentity.Structural<'T>))) with + source.PushTransform { new TransformFactory<'T,'T>() with + override __.Compose _ _ next = + upcast { new Transform<'T,'V,HashSet<'T>>(next,HashSet HashIdentity.Structural) with override this.ProcessNext (input:'T) : bool = - if this.Value.Add input then TailCall.avoid (next.ProcessNext input) - else false } } - + this.State.Add input && TailCall.avoid (next.ProcessNext input) }} [] let inline distinctBy (keyf:'T->'Key) (source:ISeq<'T>) :ISeq<'T> when 'Key:equality = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,HashSet<'Key>> - (Upcast.iCompletionChain next,(HashSet<'Key>(HashIdentity.Structural<'Key>))) with + source.PushTransform { new TransformFactory<'T,'T>() with + override __.Compose _ _ next = + upcast { new Transform<'T,'V,HashSet<'Key>> (next,HashSet HashIdentity.Structural) with override this.ProcessNext (input:'T) : bool = - if this.Value.Add (keyf input) then TailCall.avoid (next.ProcessNext input) - else false } } - + this.State.Add (keyf input) && TailCall.avoid (next.ProcessNext input) }} [] - let inline max (source: ISeq<'T>) : 'T when 'T:comparison = - source - |> foreach (fun _ -> - { new FolderWithOnComplete<'T,Values>(Values<_,_>(true, Unchecked.defaultof<'T>)) with + let inline max (source:ISeq<'T>) : 'T when 'T:comparison = + source.Fold (fun _ -> + upcast { new FolderWithPostProcessing<'T,'T,bool>(Unchecked.defaultof<'T>,true) with override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value - elif value > this.Value._2 then - this.Value._2 <- value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + if this.State then + this.State <- false + this.Result <- value + elif value > this.Result then + this.Result <- value + Unchecked.defaultof<_> (* return value unused in Fold context *) override this.OnComplete _ = - if this.Value._1 then + if this.State then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun max -> max.Value._2 - + override this.OnDispose () = () }) [] - let inline maxBy (f :'T -> 'U) (source: ISeq<'T>) : 'T when 'U:comparison = - source - |> foreach (fun _ -> - { new FolderWithOnComplete<'T,Values>(Values<_,_,_>(true,Unchecked.defaultof<'U>,Unchecked.defaultof<'T>)) with + let inline maxBy (f:'T->'U) (source:ISeq<'T>) : 'T when 'U:comparison = + source.Fold (fun _ -> + upcast { new FolderWithPostProcessing<'T,'T,Values>(Unchecked.defaultof<'T>,Values<_,_>(true,Unchecked.defaultof<'U>)) with override this.ProcessNext value = - match this.Value._1, f value with + match this.State._1, f value with | true, valueU -> - this.Value._1 <- false - this.Value._2 <- valueU - this.Value._3 <- value - | false, valueU when valueU > this.Value._2 -> - this.Value._2 <- valueU - this.Value._3 <- value + this.State._1 <- false + this.State._2 <- valueU + this.Result <- value + | false, valueU when valueU > this.State._2 -> + this.State._2 <- valueU + this.Result <- value | _ -> () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + Unchecked.defaultof<_> (* return value unused in Fold context *) override this.OnComplete _ = - if this.Value._1 then + if this.State._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun min -> min.Value._3 - + override this.OnDispose () = () }) [] - let inline min (source: ISeq< 'T>) : 'T when 'T:comparison = - source - |> foreach (fun _ -> - { new FolderWithOnComplete<'T,Values>(Values<_,_>(true, Unchecked.defaultof<'T>)) with + let inline min (source:ISeq<'T>) : 'T when 'T:comparison = + source.Fold (fun _ -> + upcast { new FolderWithPostProcessing<'T,'T,bool>(Unchecked.defaultof<'T>,true) with override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value - elif value < this.Value._2 then - this.Value._2 <- value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + if this.State then + this.State <- false + this.Result <- value + elif value < this.Result then + this.Result <- value + Unchecked.defaultof<_> (* return value unused in Fold context *) override this.OnComplete _ = - if this.Value._1 then + if this.State then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun min -> min.Value._2 - + override this.OnDispose () = () }) [] - let inline minBy (f : 'T -> 'U) (source: ISeq<'T>) : 'T = - source - |> foreach (fun _ -> - { new FolderWithOnComplete< 'T,Values>(Values<_,_,_>(true,Unchecked.defaultof< 'U>,Unchecked.defaultof< 'T>)) with + let inline minBy (f:'T->'U) (source:ISeq<'T>) : 'T = + source.Fold (fun _ -> + upcast { new FolderWithPostProcessing<'T,'T,Values>(Unchecked.defaultof<'T>,Values<_,_>(true,Unchecked.defaultof< 'U>)) with override this.ProcessNext value = - match this.Value._1, f value with + match this.State._1, f value with | true, valueU -> - this.Value._1 <- false - this.Value._2 <- valueU - this.Value._3 <- value - | false, valueU when valueU < this.Value._2 -> - this.Value._2 <- valueU - this.Value._3 <- value + this.State._1 <- false + this.State._2 <- valueU + this.Result <- value + | false, valueU when valueU < this.State._2 -> + this.State._2 <- valueU + this.Result <- value | _ -> () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + Unchecked.defaultof<_> (* return value unused in Fold context *) override this.OnComplete _ = - if this.Value._1 then + if this.State._1 then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun min -> min.Value._3 - + override this.OnDispose () = () }) [] - let inline pairwise (source:ISeq<'T>) : ISeq<'T * 'T> = - source |> compose { new SeqFactory<'T,'T * 'T>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'U,Values> - ( Upcast.iCompletionChain next - , Values - ((* isFirst = _1*) true - ,(* lastValue = _2*) Unchecked.defaultof<'T> - ) - ) with - override self.ProcessNext (input:'T) : bool = - if (*isFirst*) self.Value._1 then - self.Value._2 (*lastValue*)<- input - self.Value._1 (*isFirst*)<- false + let pairwise (source:ISeq<'T>) : ISeq<'T*'T> = + source.PushTransform { new TransformFactory<'T,'T * 'T>() with + override __.Compose _ _ next = + upcast { new Transform<'T,'U,Values>(next, Values(true, Unchecked.defaultof<'T>)) with + // member this.isFirst = this.State._1 + // member this.lastValue = this.State._2 + override this.ProcessNext (input:'T) : bool = + if this.State._1 then + this.State._2 <- input + this.State._1 <- false false else - let currentPair = self.Value._2, input - self.Value._2 (*lastValue*)<- input - TailCall.avoid (next.ProcessNext currentPair) - }} - + let currentPair = this.State._2, input + this.State._2 <- input + TailCall.avoid (next.ProcessNext currentPair) }} [] - let inline reduce (f:'T->'T->'T) (source : ISeq<'T>) : 'T = - source - |> foreach (fun _ -> - { new FolderWithOnComplete<'T, Values>(Values<_,_>(true, Unchecked.defaultof<'T>)) with + let inline reduce (f:'T->'T->'T) (source: ISeq<'T>) : 'T = + source.Fold (fun _ -> + upcast { new FolderWithPostProcessing<'T,'T,bool>(Unchecked.defaultof<'T>,true) with override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value + if this.State then + this.State <- false + this.Result <- value else - this.Value._2 <- f this.Value._2 value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) + this.Result <- f this.Result value + Unchecked.defaultof<_> (* return value unused in Fold context *) override this.OnComplete _ = - if this.Value._1 then + if this.State then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - }) - |> fun reduced -> reduced.Value._2 - + override this.OnDispose () = () }) [] - let inline scan (folder:'State->'T->'State) (initialState: 'State) (source:ISeq<'T>) :ISeq<'State> = - source |> compose { new SeqFactory<'T,'State>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,'State>(Upcast.iCompletionChain next, initialState) with + let inline scan (folder:'State->'T->'State) (initialState:'State) (source:ISeq<'T>) :ISeq<'State> = + source.PushTransform { new TransformFactory<'T,'State>() with + override __.Compose _ _ next = + upcast { new Transform<'T,'V,'State>(next, initialState) with override this.ProcessNext (input:'T) : bool = - this.Value <- folder this.Value input - TailCall.avoid (next.ProcessNext this.Value) } } - + this.State <- folder this.State input + TailCall.avoid (next.ProcessNext this.State) } } [] - let inline skip (errorString:string) (skipCount:int) (source:ISeq<'T>) : ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { - new ConsumerChainedWithStateAndCleanup<'T,'U,int>(Upcast.iCompletionChain next,(*count*)0) with - - override self.ProcessNext (input:'T) : bool = - if (*count*) self.Value < skipCount then - self.Value <- self.Value + 1 + let skip (skipCount:int) (source:ISeq<'T>) : ISeq<'T> = + source.PushTransform { new TransformFactory<'T,'T>() with + override __.Compose _ _ next = + let mutable this = Unchecked.defaultof> + let skipper = + { new TransformWithPostProcessing<'T,'U,int>(next,(*count*)0) with + // member this.count = this.State + override this.ProcessNext (input:'T) : bool = + if this.State < skipCount then + this.State <- this.State + 1 false else TailCall.avoid (next.ProcessNext input) - override self.OnDispose () = () - override self.OnComplete _ = - if (*count*) self.Value < skipCount then - let x = skipCount - self.Value + override this.OnComplete _ = + if this.State < skipCount then + let x = skipCount - this.State invalidOpFmt "{0}\ntried to skip {1} {2} past the end of the seq" - [|errorString; x; (if x=1 then "element" else "elements")|] + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + override this.OnDispose () = () - interface ISkipping with - member self.Skipping () = - let self = self :?> ConsumerChainedWithState<'T,'U,int> - if (*count*) self.Value < skipCount then - self.Value <- self.Value + 1 + interface ISkipable with + member __.CanSkip () = + if this.State < skipCount then + this.State <- this.State + 1 true else - false - }} - + false } + this <- skipper + upcast this } [] let inline skipWhile (predicate:'T->bool) (source:ISeq<'T>) : ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithState<'T,'V,bool>(Upcast.iCompletionChain next,true) with - override self.ProcessNext (input:'T) : bool = - if self.Value (*skip*) then - self.Value <- predicate input - if self.Value (*skip*) then + source.PushTransform { new TransformFactory<'T,'T>() with + override __.Compose _ _ next = + upcast { new Transform<'T,'V,bool>(next,true) with + // member this.skip = this.State + override this.ProcessNext (input:'T) : bool = + if this.State then + this.State <- predicate input + if this.State then false else TailCall.avoid (next.ProcessNext input) else TailCall.avoid (next.ProcessNext input) }} - [] - let inline sum (source:ISeq< ^T>) : ^T - when ^T:(static member Zero : ^T) - and ^T:(static member (+) : ^T * ^T -> ^T) = - source - |> foreach (fun _ -> - { new Folder< ^T,^T> (LanguagePrimitives.GenericZero) with + let inline sum (source:ISeq<'T>) = + source.Fold (fun _ -> + upcast { new Folder<'T,'T,NoValue> (LanguagePrimitives.GenericZero,Unchecked.defaultof) with override this.ProcessNext value = - this.Value <- Checked.(+) this.Value value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun sum -> sum.Value - + this.Result <- Checked.(+) this.Result value + Unchecked.defaultof<_> (* return value unused in Fold context *) }) [] - let inline sumBy (f : 'T -> ^U) (source: ISeq<'T>) : ^U - when ^U:(static member Zero : ^U) - and ^U:(static member (+) : ^U * ^U -> ^U) = - source - |> foreach (fun _ -> - { new Folder<'T,'U> (LanguagePrimitives.GenericZero< ^U>) with + let inline sumBy (f:'T->'U) (source:ISeq<'T>) = + source.Fold (fun _ -> + upcast { new Folder<'T,'U,NoValue> (LanguagePrimitives.GenericZero<'U>,Unchecked.defaultof) with override this.ProcessNext value = - this.Value <- Checked.(+) this.Value (f value) - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun sum -> sum.Value - + this.Result <- Checked.(+) this.Result (f value) + Unchecked.defaultof<_> (* return value unused in Fold context *) }) [] - let inline take (errorString:string) (takeCount:int) (source:ISeq<'T>) : ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create outOfBand pipelineIdx next = - upcast { - new ConsumerChainedWithStateAndCleanup<'T,'U,int>(Upcast.iCompletionChain next,(*count*)0) with - override self.ProcessNext (input:'T) : bool = - if (*count*) self.Value < takeCount then - self.Value <- self.Value + 1 - if self.Value = takeCount then - outOfBand.StopFurtherProcessing pipelineIdx - TailCall.avoid (next.ProcessNext input) - else + let take (takeCount:int) (source:ISeq<'T>) : ISeq<'T> = + source.PushTransform { new TransformFactory<'T,'T>() with + member __.Compose outOfBand pipelineIdx next = + upcast { new TransformWithPostProcessing<'T,'U,int>(next,(*count*)0) with + // member this.count = this.State + override this.ProcessNext (input:'T) : bool = + if this.State < takeCount then + this.State <- this.State + 1 + if this.State = takeCount then outOfBand.StopFurtherProcessing pipelineIdx - false - - override this.OnDispose () = () - override this.OnComplete terminatingIdx = - if terminatingIdx < pipelineIdx && this.Value < takeCount then - let x = takeCount - this.Value - invalidOpFmt "tried to take {0} {1} past the end of the seq" - [|errorString; x; (if x=1 then "element" else "elements")|] - }} + TailCall.avoid (next.ProcessNext input) + else + outOfBand.StopFurtherProcessing pipelineIdx + false + override this.OnComplete terminatingIdx = + if terminatingIdx < pipelineIdx && this.State < takeCount then + let x = takeCount - this.State + invalidOpFmt "tried to take {0} {1} past the end of the seq" + [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|] + override this.OnDispose () = () }} [] let inline takeWhile (predicate:'T->bool) (source:ISeq<'T>) : ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create outOfBand pipeIdx next = - upcast { new ConsumerChained<'T,'V>(Upcast.iCompletionChain next) with + source.PushTransform { new TransformFactory<'T,'T>() with + member __.Compose outOfBand pipeIdx next = + upcast { new Transform<'T,'V,NoValue>(next,Unchecked.defaultof) with override __.ProcessNext (input:'T) : bool = if predicate input then TailCall.avoid (next.ProcessNext input) else outOfBand.StopFurtherProcessing pipeIdx - false - }} - + false }} [] - let inline tail errorString (source:ISeq<'T>) :ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create _ _ next = - upcast { new ConsumerChainedWithStateAndCleanup<'T,'V,bool>(Upcast.iCompletionChain next,(*first*) true) with - override self.ProcessNext (input:'T) : bool = - if (*first*) self.Value then - self.Value <- false + let tail (source:ISeq<'T>) : ISeq<'T> = + source.PushTransform { new TransformFactory<'T,'T>() with + member __.Compose _ _ next = + upcast { new TransformWithPostProcessing<'T,'V,bool>(next,true) with + // member this.isFirst = this.State + override this.ProcessNext (input:'T) : bool = + if this.State then + this.State <- false false else TailCall.avoid (next.ProcessNext input) - - override self.OnDispose () = () - override self.OnComplete _ = - if (*first*) self.Value then - invalidArg "source" errorString - }} - + override this.OnComplete _ = + if this.State then + invalidArg "source" (SR.GetString SR.notEnoughElements) + override this.OnDispose () = () }} [] - let inline truncate (truncateCount:int) (source:ISeq<'T>) : ISeq<'T> = - source |> compose { new SeqFactory<'T,'T>() with - member __.Create outOfBand pipeIdx next = - upcast { - new ConsumerChainedWithState<'T,'U,int>(Upcast.iCompletionChain next,(*count*)0) with - override self.ProcessNext (input:'T) : bool = - if (*count*) self.Value < truncateCount then - self.Value <- self.Value + 1 - if self.Value = truncateCount then - outOfBand.StopFurtherProcessing pipeIdx - TailCall.avoid (next.ProcessNext input) - else + let truncate (truncateCount:int) (source:ISeq<'T>) : ISeq<'T> = + source.PushTransform { new TransformFactory<'T,'T>() with + member __.Compose outOfBand pipeIdx next = + upcast { new Transform<'T,'U,int>(next,(*count*)0) with + // member this.count = this.State + override this.ProcessNext (input:'T) : bool = + if this.State < truncateCount then + this.State <- this.State + 1 + if this.State = truncateCount then outOfBand.StopFurtherProcessing pipeIdx - false - }} - + TailCall.avoid (next.ProcessNext input) + else + outOfBand.StopFurtherProcessing pipeIdx + false }} [] - let inline indexed source = + let indexed source = mapi (fun i x -> i,x) source - [] - let tryItem (errorString:string) index (source:ISeq<'T>) = + let tryItem index (source:ISeq<'T>) = if index < 0 then None else - source |> skip errorString index |> tryHead - + source |> skip index |> tryHead [] - let tryPick f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, Option<'U>> (None) with + let inline tryPick f (source:ISeq<'T>) = + source.Fold (fun pipeIdx -> + upcast { new Folder<'T, Option<'U>,NoValue> (None,Unchecked.defaultof) with override this.ProcessNext value = match f value with | (Some _) as some -> - this.Value <- some - halt () + this.Result <- some + this.StopFurtherProcessing pipeIdx | None -> () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun pick -> pick.Value - + Unchecked.defaultof<_> (* return value unused in Fold context *) }) [] - let tryFind f (source:ISeq<'T>) = - source - |> foreach (fun halt -> - { new Folder<'T, Option<'T>> (None) with + let inline tryFind f (source:ISeq<'T>) = + source.Fold (fun pipeIdx -> + upcast { new Folder<'T, Option<'T>,NoValue> (None,Unchecked.defaultof) with override this.ProcessNext value = if f value then - this.Value <- Some value - halt () - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun find -> find.Value - + this.Result <- Some value + this.StopFurtherProcessing pipeIdx + Unchecked.defaultof<_> (* return value unused in Fold context *) }) [] let inline tryFindIndex (predicate:'T->bool) (source:ISeq<'T>) : int option = - source - |> foreach (fun halt -> - { new Folder<'T, Values, int>>(Values<_,_>(None, 0)) with + source.Fold (fun pipeIdx -> + { new Folder<'T, Option, int>(None, 0) with + // member this.index = this.State override this.ProcessNext value = if predicate value then - this.Value._1 <- Some(this.Value._2) - halt () + this.Result <- Some this.State + this.StopFurtherProcessing pipeIdx else - this.Value._2 <- this.Value._2 + 1 - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun tried -> tried.Value._1 + this.State <- this.State + 1 + Unchecked.defaultof<_> (* return value unused in Fold context *) }) [] - let inline tryLast (source :ISeq<'T>) : 'T option = - source - |> foreach (fun _ -> - { new Folder<'T, Values>(Values(true, Unchecked.defaultof<'T>)) with + let tryLast (source:ISeq<'T>) : 'T option = + source.Fold (fun _ -> + upcast { new FolderWithPostProcessing<'T,option<'T>,Values>(None,Values(true, Unchecked.defaultof<'T>)) with + // member this.noItems = this.State._1 + // memebr this.last = this.State._2 override this.ProcessNext value = - if this.Value._1 then - this.Value._1 <- false - this.Value._2 <- value - Unchecked.defaultof<_> (* return value unsed in ForEach context *) }) - |> fun tried -> - if tried.Value._1 then - None - else - Some tried.Value._2 + if this.State._1 then + this.State._1 <- false + this.State._2 <- value + Unchecked.defaultof<_> (* return value unused in Fold context *) + override this.OnComplete _ = + if not this.State._1 then + this.Result <- Some this.State._2 + override this.OnDispose () = () }) + [] + let last (source:ISeq<_>) = + match tryLast source with + | None -> invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + | Some x -> x [] - let inline windowed (windowSize:int) (source:ISeq<'T>) : ISeq<'T[]> = - source |> compose { new SeqFactory<'T,'T[]>() with - member __.Create outOfBand pipeIdx next = + let windowed (windowSize:int) (source:ISeq<'T>) : ISeq<'T[]> = + source.PushTransform { new TransformFactory<'T,'T[]>() with + member __.Compose outOfBand pipeIdx next = upcast { - new ConsumerChainedWithState<'T,'U,Values<'T[],int,int>> - ( Upcast.iCompletionChain next - , Values<'T[],int,int> - ((*circularBuffer = _1 *) Array.zeroCreateUnchecked windowSize - ,(* idx = _2 *) 0 - ,(* priming = _3 *) windowSize-1 - ) - ) with - override self.ProcessNext (input:'T) : bool = - self.Value._1.[(* idx *)self.Value._2] <- input - - self.Value._2 <- (* idx *)self.Value._2 + 1 - if (* idx *) self.Value._2 = windowSize then - self.Value._2 <- 0 - - if (* priming *) self.Value._3 > 0 then - self.Value._3 <- self.Value._3 - 1 + new Transform<'T,'U,Values<'T[],int,int>>(next,Values<'T[],int,int>(Array.zeroCreateUnchecked windowSize, 0, windowSize-1)) with + override this.ProcessNext (input:'T) : bool = + let circularBuffer = this.State._1 + let idx : byref<_> = &this.State._2 + let priming : byref<_> = &this.State._3 + + circularBuffer.[idx] <- input + + idx <- idx + 1 + if idx = windowSize then + idx <- 0 + + if priming > 0 then + priming <- priming - 1 false + elif windowSize < 32 then + let idx = idx + let window :'T [] = Array.init windowSize (fun i -> circularBuffer.[(idx+i) % windowSize]: 'T) + TailCall.avoid (next.ProcessNext window) else - if windowSize < 32 then - let window :'T [] = Array.init windowSize (fun i -> self.Value._1.[((* idx *)self.Value._2+i) % windowSize]: 'T) - TailCall.avoid (next.ProcessNext window) - else - let window = Array.zeroCreateUnchecked windowSize - Array.Copy((*circularBuffer*)self.Value._1, (* idx *)self.Value._2, window, 0, windowSize - (* idx *)self.Value._2) - Array.Copy((*circularBuffer*)self.Value._1, 0, window, windowSize - (* idx *)self.Value._2, (* idx *)self.Value._2) - TailCall.avoid (next.ProcessNext window) - - }} + let window = Array.zeroCreateUnchecked windowSize + Array.Copy (circularBuffer, idx, window, 0, windowSize - idx) + Array.Copy (circularBuffer, 0, window, windowSize - idx, idx) + TailCall.avoid (next.ProcessNext window) }} + + [] + let concat (sources:ISeq<#ISeq<'T>>) : ISeq<'T> = + Upcast.seq (Enumerable.ConcatEnumerable sources) + + [] + let append (source1:ISeq<'T>) (source2: ISeq<'T>) : ISeq<'T> = + match source1 with + | :? Enumerable.EnumerableBase<'T> as s -> s.Append source2 + | _ -> Upcast.seq (new Enumerable.AppendEnumerable<_>([source2; source1])) + + [] + let delay (delayed:unit->ISeq<'T>) = + Upcast.seq (Enumerable.SeqDelayed (delayed, 1)) + + module internal GroupBy = + let inline private impl (comparer:IEqualityComparer<'SafeKey>) (keyf:'T->'SafeKey) (getKey:'SafeKey->'Key) (source:ISeq<'T>) = + source.Fold (fun _ -> + upcast { new FolderWithPostProcessing<'T,ISeq<'Key*ISeq<'T>>,_>(Unchecked.defaultof<_>,Dictionary comparer) with + override this.ProcessNext v = + let safeKey = keyf v + match this.State.TryGetValue safeKey with + | false, _ -> + let prev = ResizeArray () + this.State.[safeKey] <- prev + prev.Add v + | true, prev -> prev.Add v + Unchecked.defaultof<_> (* return value unused in Fold context *) + + override this.OnComplete _ = + let maxWastage = 4 + for value in this.State.Values do + if value.Capacity - value.Count > maxWastage then value.TrimExcess () + + this.Result <- + this.State + |> ofSeq + |> map (fun kv -> getKey kv.Key, ofResizeArrayUnchecked kv.Value) + + override this.OnDispose () = () }) + + let inline byVal (keyf:'T->'Key) (source:ISeq<'T>) = + delay (fun () -> impl HashIdentity.Structural<'Key> keyf id source) + + let inline byRef (keyf:'T->'Key) (source:ISeq<'T>) = + delay (fun () -> impl (valueComparer<'Key> ()) (keyf >> Value) (fun v -> v._1) source) + + [] + let inline groupByVal<'T,'Key when 'Key : equality and 'Key : struct> (keyf:'T->'Key) (source:ISeq<'T>) = + GroupBy.byVal keyf source + + [] + let inline groupByRef<'T,'Key when 'Key : equality and 'Key : not struct> (keyf:'T->'Key) (source:ISeq<'T>) = + GroupBy.byRef keyf source + + module CountBy = + let inline private impl (comparer:IEqualityComparer<'SafeKey>) (keyf:'T->'SafeKey) (getKey:'SafeKey->'Key) (source:ISeq<'T>) = + source.Fold (fun _ -> + upcast { new FolderWithPostProcessing<'T,ISeq<'Key*int>,_>(Unchecked.defaultof<_>,Dictionary comparer) with + override this.ProcessNext v = + let safeKey = keyf v + this.State.[safeKey] <- + match this.State.TryGetValue safeKey with + | true, prev -> prev + 1 + | false, _ -> 1 + Unchecked.defaultof<_> (* return value unused in Fold context *) + + override this.OnComplete _ = + this.Result <- + this.State + |> ofSeq + |> map (fun group -> getKey group.Key, group.Value) + + override this.OnDispose () = () }) + + let inline byVal (keyf:'T->'Key) (source:ISeq<'T>) = + delay (fun () -> impl HashIdentity.Structural<'Key> keyf id source) + + let inline byRef (keyf:'T->'Key) (source:ISeq<'T>) = + delay (fun () -> impl (valueComparer<'Key> ()) (keyf >> Value) (fun v -> v._1) source) + + [] + let inline countByVal<'T,'Key when 'Key : equality and 'Key : struct> (projection:'T -> 'Key) (source:ISeq<'T>) = + CountBy.byVal projection source + + [] + let inline countByRef<'T,'Key when 'Key : equality and 'Key : not struct> (projection:'T -> 'Key) (source:ISeq<'T>) = + CountBy.byRef projection source + + [] + let toArray (source:ISeq<'T>) = + match box source with + | :? ('T[]) as res -> (res.Clone() :?> 'T[]) + | :? ('T list) as res -> List.toArray res + | :? ICollection<'T> as res -> + // Directly create an array and copy ourselves. + // This avoids an extra copy if using ResizeArray in fallback below. + let arr = Array.zeroCreateUnchecked res.Count + res.CopyTo(arr, 0) + arr + | _ -> + source.Fold (fun _ -> + upcast { new FolderWithPostProcessing<'T,array<'T>,_>(Unchecked.defaultof<_>,ResizeArray ()) with + override this.ProcessNext v = + this.State.Add v + Unchecked.defaultof<_> (* return value unused in Fold context *) + override this.OnComplete _ = + this.Result <- this.State.ToArray () + override this.OnDispose () = () }) + + [] + let sortBy keyf source = + delay (fun () -> + let array = source |> toArray + Array.stableSortInPlaceBy keyf array + Upcast.seq (Array.Enumerable (array, IdentityFactory.Instance, 1))) + + [] + let sort source = + delay (fun () -> + let array = source |> toArray + Array.stableSortInPlace array + Upcast.seq (Array.Enumerable (array, IdentityFactory.Instance, 1))) + + [] + let sortWith f source = + delay (fun () -> + let array = source |> toArray + Array.stableSortInPlaceWith f array + Upcast.seq (Array.Enumerable (array, IdentityFactory.Instance, 1))) + + [] + let rev source = + delay (fun () -> + let array = source |> toArray + Array.Reverse array + Upcast.seq (Array.Enumerable (array, IdentityFactory.Instance, 1))) + + [] + let permute f (source:ISeq<_>) = + delay (fun () -> + source + |> toArray + |> Array.permute f + |> fun array -> Upcast.seq (Array.Enumerable (array, IdentityFactory.Instance, 1))) diff --git a/src/fsharp/FSharp.Core/seqcomposer.fsi b/src/fsharp/FSharp.Core/seqcomposer.fsi index c4f352f0988..1df1b9ee772 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fsi +++ b/src/fsharp/FSharp.Core/seqcomposer.fsi @@ -14,6 +14,13 @@ namespace Microsoft.FSharp.Collections [] type NoValue = struct end + /// Values is a mutable struct. It can be embedded within the folder type + /// if two values are required for the calculation. + [] + type Value<'a> = + new : a:'a -> Value<'a> + val mutable _1: 'a + /// Values is a mutable struct. It can be embedded within the folder type /// if two values are required for the calculation. [] @@ -38,11 +45,10 @@ namespace Microsoft.FSharp.Collections type IOutOfBand = abstract StopFurtherProcessing : PipeIdx -> unit - /// ICompletionChain is used to correctly handle cleaning up of the pipeline. A - /// base implementation is provided in Consumer, and should not be overwritten. Consumer - /// provides it's own OnComplete and OnDispose function which should be used to handle - /// a particular consumers cleanup. - type ICompletionChain = + /// Activity is the root class for chains of activities. It is in a non-generic + /// form so that it can be used by subsequent activities + [] + type Activity = /// OnComplete is used to determine if the object has been processed correctly, /// and possibly throw exceptions to denote incorrect application (i.e. such as a Take /// operation which didn't have a source at least as large as was required). It is @@ -53,357 +59,70 @@ namespace Microsoft.FSharp.Collections /// after the enumeration has completed. abstract ChainDispose : stopTailCall:byref -> unit - /// Consumer is the base class of all elements within the pipeline + /// Activity is the base class of all elements within the pipeline [] - type Consumer<'T,'U> = - interface ICompletionChain - new : unit -> Consumer<'T,'U> + type Activity<'T,'U> = + inherit Activity + new : unit -> Activity<'T,'U> abstract member ProcessNext : input:'T -> bool [] - type ConsumerWithState<'T,'U,'Value> = - inherit Consumer<'T,'U> - val mutable Value : 'Value - new : init:'Value -> ConsumerWithState<'T,'U,'Value> - - [] - type ConsumerChainedWithState<'T,'U,'Value> = - inherit ConsumerWithState<'T,'U,'Value> - interface ICompletionChain - val private Next : ICompletionChain - new : next:ICompletionChain * init:'Value -> ConsumerChainedWithState<'T,'U,'Value> - - [] - type ConsumerChained<'T,'U> = - inherit ConsumerChainedWithState<'T,'U,NoValue> - new : next:ICompletionChain -> ConsumerChained<'T,'U> + type Transform<'T,'U,'State> = + inherit Activity<'T,'U> + new : next:Activity * 'State -> Transform<'T,'U,'State> + val mutable State : 'State + val private Next : Activity [] - type ConsumerChainedWithStateAndCleanup<'T,'U,'Value> = - inherit ConsumerChainedWithState<'T,'U,'Value> - interface ICompletionChain - + type TransformWithPostProcessing<'T,'U,'State> = + inherit Transform<'T,'U,'State> + new : next:Activity * 'State -> TransformWithPostProcessing<'T,'U,'State> abstract OnComplete : PipeIdx -> unit abstract OnDispose : unit -> unit - new : next:ICompletionChain * init:'Value -> ConsumerChainedWithStateAndCleanup<'T,'U,'Value> - - [] - type ConsumerChainedWithCleanup<'T,'U> = - inherit ConsumerChainedWithStateAndCleanup<'T,'U,NoValue> - new : next:ICompletionChain -> ConsumerChainedWithCleanup<'T,'U> - /// Folder is a base class to assist with fold-like operations. It's intended usage /// is as a base class for an object expression that will be used from within - /// the ForEach function. + /// the Fold function. [] - type Folder<'T,'Value> = - inherit ConsumerWithState<'T,'T,'Value> - new : init:'Value -> Folder<'T,'Value> + type Folder<'T,'Result,'State> = + inherit Activity<'T,'T> + new : 'Result*'State -> Folder<'T,'Result,'State> + interface IOutOfBand + val mutable State : 'State + val mutable Result : 'Result + val mutable HaltedIdx : int + member StopFurtherProcessing : PipeIdx -> unit [] - type FolderWithOnComplete<'T, 'Value> = - inherit Folder<'T,'Value> - interface ICompletionChain - + type FolderWithPostProcessing<'T,'Result,'State> = + inherit Folder<'T,'Result,'State> + new : 'Result*'State -> FolderWithPostProcessing<'T,'Result,'State> + abstract OnDispose : unit -> unit abstract OnComplete : PipeIdx -> unit - new : init:'Value -> FolderWithOnComplete<'T,'Value> - [] - type SeqFactory<'T,'U> = - new : unit -> SeqFactory<'T,'U> - abstract PipeIdx : PipeIdx - default PipeIdx : PipeIdx - abstract member Create : IOutOfBand -> PipeIdx -> Consumer<'U,'V> -> Consumer<'T,'V> + type TransformFactory<'T,'U> = + new : unit -> TransformFactory<'T,'U> + abstract member Compose : IOutOfBand -> PipeIdx -> Activity<'U,'V> -> Activity<'T,'V> type ISeq<'T> = inherit System.Collections.Generic.IEnumerable<'T> - abstract member Compose : SeqFactory<'T,'U> -> ISeq<'U> - abstract member ForEach : f:((unit -> unit) -> 'a) -> 'a when 'a :> Consumer<'T,'T> + abstract member PushTransform : TransformFactory<'T,'U> -> ISeq<'U> + abstract member Fold<'Result,'State> : f:(PipeIdx->Folder<'T,'Result,'State>) -> 'Result open Core - type ComposedFactory<'T,'U,'V> = - class - inherit SeqFactory<'T,'V> - private new : first: SeqFactory<'T,'U> * - second: SeqFactory<'U,'V> * - secondPipeIdx: PipeIdx -> - ComposedFactory<'T,'U,'V> - static member - Combine : first: SeqFactory<'T,'U> -> - second: SeqFactory<'U,'V> -> - SeqFactory<'T,'V> - end - and IdentityFactory<'T> = - class - inherit SeqFactory<'T,'T> - new : unit -> IdentityFactory<'T> - static member Instance : SeqFactory<'T,'T> - end - - and ISkipping = - interface - abstract member Skipping : unit -> bool - end - - type SeqProcessNextStates = - | InProcess = 0 - | NotStarted = 1 - | Finished = 2 - type Result<'T> = - class - interface IOutOfBand - new : unit -> Result<'T> - member Current : 'T - member HaltedIdx : int - member SeqState : SeqProcessNextStates - member Current : 'T with set - member SeqState : SeqProcessNextStates with set - end - type SetResult<'T> = - class - inherit Consumer<'T,'T> - new : result: Result<'T> -> SetResult<'T> - override ProcessNext : input:'T -> bool - end - type OutOfBand = - class - interface IOutOfBand - new : unit -> OutOfBand - member HaltedIdx : int - end - module ForEach = begin - val enumerable : - enumerable:IEnumerable<'T> -> - outOfBand: OutOfBand -> - consumer: Consumer<'T,'U> -> unit - val array : - array:'T array -> - outOfBand: OutOfBand -> - consumer: Consumer<'T,'U> -> unit - val list : - alist:'T list -> - outOfBand: OutOfBand -> - consumer: Consumer<'T,'U> -> unit - val unfold : - generator:('S -> ('T * 'S) option) -> - state:'S -> - outOfBand: OutOfBand -> - consumer: Consumer<'T,'U> -> unit - val makeIsSkipping : - consumer: Consumer<'T,'U> -> (unit -> bool) - val init : - f:(int -> 'T) -> - terminatingIdx:int -> - outOfBand: OutOfBand -> - consumer: Consumer<'T,'U> -> unit - val execute : - f:((unit -> unit) -> 'a) -> - current: SeqFactory<'T,'U> -> - executeOn:( OutOfBand -> Consumer<'T,'U> -> - unit) -> 'a when 'a :> Consumer<'U,'U> - end - module Enumerable = begin - type Empty<'T> = - class - interface IDisposable - interface IEnumerator - interface IEnumerator<'T> - new : unit -> Empty<'T> - end - type EmptyEnumerators<'T> = - class - new : unit -> EmptyEnumerators<'T> - static member Element : IEnumerator<'T> - end - [] - type EnumeratorBase<'T> = - class - interface IEnumerator<'T> - interface IEnumerator - interface IDisposable - new : result: Result<'T> * - seqComponent: ICompletionChain -> - EnumeratorBase<'T> - end - and [] EnumerableBase<'T> = - class - interface ISeq<'T> - interface IEnumerable<'T> - interface IEnumerable - new : unit -> EnumerableBase<'T> - abstract member - Append : seq<'T> -> IEnumerable<'T> - override - Append : source:seq<'T> -> IEnumerable<'T> - end - and Enumerator<'T,'U> = - class - inherit EnumeratorBase<'U> - interface IDisposable - interface IEnumerator - new : source:IEnumerator<'T> * - seqComponent: Consumer<'T,'U> * - result: Result<'U> -> - Enumerator<'T,'U> - end - and Enumerable<'T,'U> = - class - inherit EnumerableBase<'U> - interface ISeq<'U> - interface IEnumerable<'U> - new : enumerable:IEnumerable<'T> * - current: SeqFactory<'T,'U> -> - Enumerable<'T,'U> - end - and ConcatEnumerator<'T,'Collection when 'Collection :> seq<'T>> = - class - interface IDisposable - interface IEnumerator - interface IEnumerator<'T> - new : sources:seq<'Collection> -> - ConcatEnumerator<'T,'Collection> - end - and AppendEnumerable<'T> = - class - inherit EnumerableBase<'T> - interface ISeq<'T> - interface IEnumerable<'T> - new : sources:seq<'T> list -> AppendEnumerable<'T> - override - Append : source:seq<'T> -> - IEnumerable<'T> - end - and ConcatEnumerable<'T,'Collection when 'Collection :> seq<'T>> = - class - inherit EnumerableBase<'T> - interface ISeq<'T> - interface IEnumerable<'T> - new : sources:seq<'Collection> -> - ConcatEnumerable<'T,'Collection> - end - val create : - enumerable:IEnumerable<'a> -> - current: SeqFactory<'a,'b> -> ISeq<'b> - end - module EmptyEnumerable = begin - type Enumerable<'T> = - class - inherit Enumerable.EnumerableBase<'T> - interface ISeq<'T> - interface IEnumerable<'T> - new : unit -> Enumerable<'T> - override - Append : source:seq<'T> -> IEnumerable<'T> - static member Instance : ISeq<'T> - end - end - module Array = begin - type Enumerator<'T,'U> = - class - inherit Enumerable.EnumeratorBase<'U> - interface IEnumerator - new : delayedArray:(unit -> 'T array) * - seqComponent: Consumer<'T,'U> * - result: Result<'U> -> Enumerator<'T,'U> - end - type Enumerable<'T,'U> = - class - inherit Enumerable.EnumerableBase<'U> - interface ISeq<'U> - interface IEnumerable<'U> - new : delayedArray:(unit -> 'T array) * - current: SeqFactory<'T,'U> -> - Enumerable<'T,'U> - end - val createDelayed : - delayedArray:(unit -> 'T array) -> - current: SeqFactory<'T,'U> -> ISeq<'U> - val create : - array:'T array -> - current: SeqFactory<'T,'U> -> ISeq<'U> - val createDelayedId : - delayedArray:(unit -> 'T array) -> ISeq<'T> - val createId : array:'T array -> ISeq<'T> - end - module List = begin - type Enumerator<'T,'U> = - class - inherit Enumerable.EnumeratorBase<'U> - interface IEnumerator - new : alist:'T list * seqComponent: Consumer<'T,'U> * - result: Result<'U> -> Enumerator<'T,'U> - end - type Enumerable<'T,'U> = - class - inherit Enumerable.EnumerableBase<'U> - interface ISeq<'U> - interface IEnumerable<'U> - new : alist:'T list * current: SeqFactory<'T,'U> -> - Enumerable<'T,'U> - end - val create : - alist:'a list -> - current: SeqFactory<'a,'b> -> ISeq<'b> - end - module Unfold = begin - type Enumerator<'T,'U,'State> = - class - inherit Enumerable.EnumeratorBase<'U> - interface IEnumerator - new : generator:('State -> ('T * 'State) option) * state:'State * - seqComponent: Consumer<'T,'U> * - result: Result<'U> -> - Enumerator<'T,'U,'State> - end - type Enumerable<'T,'U,'GeneratorState> = - class - inherit Enumerable.EnumerableBase<'U> - interface ISeq<'U> - interface IEnumerable<'U> - new : generator:('GeneratorState -> ('T * 'GeneratorState) option) * - state:'GeneratorState * current: SeqFactory<'T,'U> -> - Enumerable<'T,'U,'GeneratorState> - end - end - module Init = begin - val getTerminatingIdx : count:Nullable -> int - type Enumerator<'T,'U> = - class - inherit Enumerable.EnumeratorBase<'U> - interface IEnumerator - new : count:Nullable * f:(int -> 'T) * - seqComponent: Consumer<'T,'U> * - result: Result<'U> -> Enumerator<'T,'U> - end - type Enumerable<'T,'U> = - class - inherit Enumerable.EnumerableBase<'U> - interface ISeq<'U> - interface IEnumerable<'U> - new : count:Nullable * f:(int -> 'T) * - current: SeqFactory<'T,'U> -> - Enumerable<'T,'U> - end - val upto : - lastOption:int option -> - f:(int -> 'U) -> IEnumerator<'U> - type EnumerableDecider<'T> = - class - inherit Enumerable.EnumerableBase<'T> - interface ISeq<'T> - interface IEnumerable<'T> - new : count:Nullable * f:(int -> 'T) -> - EnumerableDecider<'T> - end - end - - [] - val toComposer : source:seq<'T> -> ISeq<'T> - - val inline foreach : f:((unit -> unit) -> 'a) -> source: ISeq<'b> -> 'a when 'a :> Consumer<'b,'b> + [] + val ofResizeArrayUnchecked : ResizeArray<'T> -> ISeq<'T> + + [] + val ofList : list<'T> -> ISeq<'T> + + [] + val ofArray : array<'T> -> ISeq<'T> + + [] + val ofSeq : seq<'T> -> ISeq<'T> [] val inline average : source: ISeq< ^T> -> ^T @@ -418,10 +137,10 @@ namespace Microsoft.FSharp.Collections and ^U:(static member DivideByInt : ^U * int -> ^U) [] - val empty<'T> : ISeq<'T> + val empty<'T> : ISeq<'T> [] - val inline exactlyOne : errorString:string -> source : ISeq<'T> -> 'T + val exactlyOne : ISeq<'T> -> 'T [] val inline fold<'T,'State> : f:('State->'T->'State) -> seed:'State -> source:ISeq<'T> -> 'State @@ -430,100 +149,103 @@ namespace Microsoft.FSharp.Collections val inline fold2<'T1,'T2,'State> : folder:('State->'T1->'T2->'State) -> state:'State -> source1: ISeq<'T1> -> source2: ISeq<'T2> -> 'State [] - val unfold : generator:('State -> ('T * 'State) option) -> state:'State -> ISeq<'T> + val unfold : generator:('State -> option<'T*'State>) -> state:'State -> ISeq<'T> [] - val initInfinite : f:(int -> 'T) -> ISeq<'T> + val initInfinite : f:(int -> 'T) -> ISeq<'T> [] - val init : count:int -> f:(int -> 'T) -> ISeq<'T> + val init : count:int -> f:(int -> 'T) -> ISeq<'T> [] - val iter : f:('T -> unit) -> source: ISeq<'T> -> unit + val inline iter : f:('T -> unit) -> source:ISeq<'T> -> unit [] val inline iter2 : f:('T->'U->unit) -> source1 : ISeq<'T> -> source2 : ISeq<'U> -> unit [] - val inline iteri2 : f:(int->'T->'U->unit) -> source1:ISeq<'T> -> source2:seq<'U> -> unit + val inline iteri2 : f:(int->'T->'U->unit) -> source1:ISeq<'T> -> source2:ISeq<'U> -> unit [] - val tryHead : source: ISeq<'T> -> 'T option + val tryHead : ISeq<'T> -> option<'T> + + [] + val head: source:ISeq<'T> -> 'T [] - val iteri : f:(int -> 'T -> unit) -> source: ISeq<'T> -> unit + val inline iteri : f:(int -> 'T -> unit) -> source:ISeq<'T> -> unit [] val inline except : itemsToExclude:seq<'T> -> source:ISeq<'T> -> ISeq<'T> when 'T:equality [] - val exists : f:('T -> bool) -> source: ISeq<'T> -> bool + val inline exists : f:('T -> bool) -> source:ISeq<'T> -> bool [] - val exists2 : predicate:('T->'U->bool) -> source1:ISeq<'T> -> source2:ISeq<'U> -> bool + val inline exists2 : predicate:('T->'U->bool) -> source1:ISeq<'T> -> source2:ISeq<'U> -> bool [] - val inline contains : element:'T -> source: ISeq<'T> -> bool when 'T : equality + val inline contains : element:'T -> source:ISeq<'T> -> bool when 'T : equality [] - val forall : f:('T -> bool) -> source: ISeq<'T> -> bool + val inline forall : f:('T -> bool) -> source:ISeq<'T> -> bool [] val inline forall2 : predicate:('T->'U->bool) -> source1:ISeq<'T> -> source2:ISeq<'U> -> bool [] - val inline filter : f:('T -> bool) -> source: ISeq<'T> -> ISeq<'T> + val inline filter : f:('T -> bool) -> source:ISeq<'T> -> ISeq<'T> [] - val inline map : f:('T -> 'U) -> source: ISeq<'T> -> ISeq<'U> + val inline map : f:('T -> 'U) -> source:ISeq<'T> -> ISeq<'U> [] val inline mapi : f:(int->'a->'b) -> source: ISeq<'a> -> ISeq<'b> [] - val inline map2<'First,'Second,'U> : map:('First->'Second->'U) -> source1:ISeq<'First> -> source2:ISeq<'Second> -> ISeq<'U> + val inline map2<'T,'U,'V> : map:('T->'U->'V) -> source1:ISeq<'T> -> source2:ISeq<'U> -> ISeq<'V> [] - val inline mapi2<'First,'Second,'U> : map:(int -> 'First->'Second->'U) -> source1:ISeq<'First> -> source2:ISeq<'Second> -> ISeq<'U> + val inline mapi2<'T,'U,'V> : map:(int -> 'T->'U->'V) -> source1:ISeq<'T> -> source2:ISeq<'U> -> ISeq<'V> [] - val inline map3<'First,'Second,'Third,'U> : map:('First->'Second->'Third->'U) -> source1:ISeq<'First> -> source2:ISeq<'Second> -> source3:ISeq<'Third> -> ISeq<'U> + val inline map3<'T,'U,'V,'W> : map:('T->'U->'V->'W) -> source1:ISeq<'T> -> source2:ISeq<'U> -> source3:ISeq<'V> -> ISeq<'W> [] - val inline compareWith : f:('T -> 'T -> int) -> source1 :ISeq<'T> -> source2:ISeq<'T> -> int + val inline compareWith : f:('T->'T->int) -> source1 :ISeq<'T> -> source2:ISeq<'T> -> int [] val inline choose : f:('a->option<'b>) -> source: ISeq<'a> -> ISeq<'b> [] - val inline distinct : source: ISeq<'T> -> ISeq<'T> when 'T:equality + val inline distinct : source:ISeq<'T> -> ISeq<'T> when 'T:equality [] - val inline distinctBy : keyf:('T->'Key) -> source: ISeq<'T> -> ISeq<'T> when 'Key:equality + val inline distinctBy : keyf:('T->'Key) -> source:ISeq<'T> -> ISeq<'T> when 'Key:equality [] - val inline max : source: ISeq<'T> -> 'T when 'T:comparison + val inline max : source:ISeq<'T> -> 'T when 'T:comparison [] - val inline maxBy : f:('T -> 'U) -> source: ISeq<'T> -> 'T when 'U:comparison + val inline maxBy : f:('T->'U) -> source:ISeq<'T> -> 'T when 'U:comparison [] - val inline min : source: ISeq<'T> -> 'T when 'T:comparison + val inline min : source:ISeq<'T> -> 'T when 'T:comparison [] - val inline minBy : f:('T -> 'U) -> source: ISeq<'T> -> 'T when 'U:comparison + val inline minBy : f:('T->'U) -> source:ISeq<'T> -> 'T when 'U:comparison [] - val inline pairwise : source:ISeq<'T> -> ISeq<'T * 'T> + val pairwise : source:ISeq<'T> -> ISeq<'T * 'T> [] - val inline reduce : f:('T->'T->'T) -> source: ISeq<'T> -> 'T + val inline reduce : f:('T->'T->'T) -> source:ISeq<'T> -> 'T [] val inline scan : folder:('State->'T->'State) -> initialState:'State -> source:ISeq<'T> -> ISeq<'State> [] - val inline skip : errorString:string -> skipCount:int -> source:ISeq<'T> -> ISeq<'T> + val skip : skipCount:int -> source:ISeq<'T> -> ISeq<'T> [] val inline skipWhile : predicate:('T->bool) -> source:ISeq<'T> -> ISeq<'T> @@ -534,39 +256,89 @@ namespace Microsoft.FSharp.Collections and 'T:(static member (+) : ^T * ^T -> ^T) [] - val inline sumBy : f :('T -> ^U) -> source: ISeq<'T> -> ^U + val inline sumBy : f :('T -> ^U) -> source:ISeq<'T> -> ^U when ^U:(static member Zero : ^U) and ^U:(static member (+) : ^U * ^U -> ^U) [] - val inline take : errorString:string -> takeCount:int -> source:ISeq<'T> -> ISeq<'T> + val take : takeCount:int -> source:ISeq<'T> -> ISeq<'T> [] val inline takeWhile : predicate:('T->bool) -> source:ISeq<'T> -> ISeq<'T> [] - val inline tail : errorString:string -> source:ISeq<'T> -> ISeq<'T> + val tail : source:ISeq<'T> -> ISeq<'T> [] - val inline truncate : truncateCount:int -> source:ISeq<'T> -> ISeq<'T> + val truncate : truncateCount:int -> source:ISeq<'T> -> ISeq<'T> [] - val inline indexed : source: ISeq<'a> -> ISeq + val indexed : source: ISeq<'a> -> ISeq [] - val tryItem : errorString:string -> index:int -> source: ISeq<'T> -> 'T option + val tryItem : index:int -> source:ISeq<'T> -> option<'T> [] - val tryPick : f:('T -> 'U option) -> source: ISeq<'T> -> Option<'U> + val inline tryPick : f:('T -> option<'U>) -> source:ISeq<'T> -> option<'U> [] - val tryFind : f:('T -> bool) -> source: ISeq<'T> -> Option<'T> + val inline tryFind : f:('T -> bool) -> source:ISeq<'T> -> option<'T> [] - val inline tryFindIndex: preidcate:('T->bool) -> source:ISeq<'T> -> int option + val inline tryFindIndex: predicate:('T->bool) -> source:ISeq<'T> -> option + + [] + val last: source:ISeq<'T> -> 'T [] - val inline tryLast : source:ISeq<'T> -> 'T option + val tryLast : source:ISeq<'T> -> option<'T> [] - val inline windowed : windowSize:int -> source:ISeq<'T> -> ISeq<'T[]> + val windowed : windowSize:int -> source:ISeq<'T> -> ISeq> + + [] + val concat : sources:ISeq<'Collection> -> ISeq<'T> when 'Collection :> ISeq<'T> + + [] + val append: source1:ISeq<'T> -> source2:ISeq<'T> -> ISeq<'T> + + [] + val delay : (unit -> ISeq<'T>) -> ISeq<'T> + + [] + val inline groupByVal : projection:('T -> 'Key) -> source:ISeq<'T> -> ISeq<'Key * ISeq<'T>> when 'Key : equality and 'Key : struct + + [] + val inline groupByRef : projection:('T -> 'Key) -> source:ISeq<'T> -> ISeq<'Key * ISeq<'T>> when 'Key : equality and 'Key : not struct + + [] + val inline countByVal : projection:('T -> 'Key) -> source:ISeq<'T> -> ISeq<'Key * int> when 'Key : equality and 'Key : struct + + [] + val inline countByRef : projection:('T -> 'Key) -> source:ISeq<'T> -> ISeq<'Key * int> when 'Key : equality and 'Key : not struct + + [] + val toArray: source:ISeq<'T> -> array<'T> + + [] + val sortBy : projection:('T->'Key) -> source:ISeq<'T> -> ISeq<'T> when 'Key : comparison + + [] + val sort : source:ISeq<'T> -> ISeq<'T> when 'T : comparison + + [] + val sortWith : comparer:('T->'T->int) -> source:ISeq<'T> -> ISeq<'T> + + [] + val rev: source:ISeq<'T> -> ISeq<'T> + + [] + val permute: indexMap:(int->int) -> source:ISeq<'T> -> ISeq<'T> + + module internal GroupBy = + val inline byVal : projection:('T -> 'Key) -> source:ISeq<'T> -> ISeq<'Key * ISeq<'T>> when 'Key : equality + val inline byRef : projection:('T -> 'Key) -> source:ISeq<'T> -> ISeq<'Key * ISeq<'T>> when 'Key : equality + + module internal CountBy = + val inline byVal : projection:('T -> 'Key) -> source:ISeq<'T> -> ISeq<'Key * int> when 'Key : equality + val inline byRef : projection:('T -> 'Key) -> source:ISeq<'T> -> ISeq<'Key * int> when 'Key : equality From e7409fef9edc57390c3ef9f5edf5092e7e273d22 Mon Sep 17 00:00:00 2001 From: Gauthier Segay Date: Sat, 4 Mar 2017 10:07:28 +0100 Subject: [PATCH 57/59] fix compile issue --- src/fsharp/FSharp.Core/seq.fs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index ab333fe3e0b..8aba11bd9ac 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -600,13 +600,6 @@ namespace Microsoft.FSharp.Collections let exactlyOne (source : seq<_>) = source |> toComposer |> Composer.exactlyOne - member this.OnComplete _ = - if this.Value._1 then - invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - elif this.Value._3 then - invalidArg "source" (SR.GetString(SR.inputSequenceTooLong)) }) - |> fun one -> one.Value._2 - [] let rev source = source |> toComposer |> Composer.rev |> Upcast.enumerable From f6d259d86f059589695242c09b20bbf49c6dc305 Mon Sep 17 00:00:00 2001 From: Paul Westcott Date: Mon, 6 Mar 2017 19:23:59 +1100 Subject: [PATCH 58/59] Syncing with my repository after rebase --- src/fsharp/FSharp.Core/seq.fs | 68 ++++++++++----------- src/fsharp/FSharp.Core/seqcomposer.fs | 83 +++++++++++++++++++------- src/fsharp/FSharp.Core/seqcomposer.fsi | 18 ++++++ 3 files changed, 108 insertions(+), 61 deletions(-) diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs index 8aba11bd9ac..2bae61d0c20 100644 --- a/src/fsharp/FSharp.Core/seq.fs +++ b/src/fsharp/FSharp.Core/seq.fs @@ -58,8 +58,7 @@ namespace Microsoft.FSharp.Collections [] let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> = - Composer.unfold generator state - |> Upcast.enumerable + Composer.unfold generator state |> Upcast.enumerable [] let empty<'T> = (EmptyEnumerable :> seq<'T>) @@ -184,7 +183,8 @@ namespace Microsoft.FSharp.Collections [] let zip source1 source2 = - map2 (fun x y -> x,y) source1 source2 + (source1 |> toComposer' "source1", source2 |> toComposer' "source2") + ||> Composer.zip |> Upcast.enumerable [] let zip3 source1 source2 source3 = @@ -244,6 +244,7 @@ namespace Microsoft.FSharp.Collections | :? ('T[]) as a -> a.Length | :? ('T list) as a -> a.Length | :? ICollection<'T> as a -> a.Count + | :? ISeq<'T> as a -> Composer.length a | _ -> use e = source.GetEnumerator() let mutable state = 0 @@ -294,7 +295,7 @@ namespace Microsoft.FSharp.Collections [] let ofList (source : 'T list) = - (source :> seq<'T>) + source |> Composer.ofList |> Upcast.enumerable [] let toList (source : seq<'T>) = @@ -304,46 +305,43 @@ namespace Microsoft.FSharp.Collections // Create a new object to ensure underlying array may not be mutated by a backdoor cast [] let ofArray (source : 'T array) = - checkNonNull "source" source - Upcast.enumerable (Composer.ofArray source) + source |> Composer.ofArray |> Upcast.enumerable [] - let toArray (source : seq<'T>) = - source |> toComposer |> Composer.toArray - - let foldArraySubRight (f:OptimizedClosures.FSharpFunc<'T,_,_>) (arr: 'T[]) start fin acc = - let mutable state = acc - for i = fin downto start do - state <- f.Invoke(arr.[i], state) - state + let toArray (source:seq<'T>) = + match source with + | :? ('T[]) as res -> (res.Clone() :?> 'T[]) + | :? ('T list) as res -> List.toArray res + | :? ICollection<'T> as res -> + // Directly create an array and copy ourselves. + // This avoids an extra copy if using ResizeArray in fallback below. + let arr = Array.zeroCreateUnchecked res.Count + res.CopyTo(arr, 0) + arr + | :? ISeq<'T> as res -> Composer.toArray res + | _ -> + let res = ResizeArray source + res.ToArray () [] let foldBack<'T,'State> f (source : seq<'T>) (x:'State) = - checkNonNull "source" source - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - let arr = toArray source - let len = arr.Length - foldArraySubRight f arr 0 (len - 1) x + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f + ((source |> toComposer), x) ||> Composer.foldBack (fun a b -> f.Invoke (a,b)) [] let foldBack2<'T1,'T2,'State> f (source1 : seq<'T1>) (source2 : seq<'T2>) (x:'State) = - let zipped = zip source1 source2 - foldBack ((<||) f) zipped x + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f + ((source1 |> toComposer' "source1"), (source2 |> toComposer' "source2"), x) + |||> Composer.foldBack2 (fun a b -> f.Invoke (a,b)) [] let reduceBack f (source : seq<'T>) = - checkNonNull "source" source - let arr = toArray source - match arr.Length with - | 0 -> invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString - | len -> - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) - foldArraySubRight f arr 0 (len - 2) arr.[len - 1] - + let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f + source |> toComposer |> Composer.reduceBack (fun a b -> f.Invoke (a,b)) + [] let singleton x = mkSeq (fun () -> IEnumerator.Singleton x) - [] let truncate n (source: seq<'T>) = if n <= 0 then empty else @@ -368,12 +366,8 @@ namespace Microsoft.FSharp.Collections source |> toArray |> Array.findBack f [] - let scanBack<'T,'State> f (source : seq<'T>) (acc:'State) = - checkNonNull "source" source - mkDelayedSeq(fun () -> - let arr = source |> toArray - let res = Array.scanSubRight f arr 0 (arr.Length - 1) acc - res :> seq<_>) + let scanBack<'T,'State> f (source:seq<'T>) (acc:'State) = + Composer.scanBack f (toComposer source) acc |> Upcast.enumerable [] let tryFindIndex p (source:seq<_>) = @@ -398,8 +392,6 @@ namespace Microsoft.FSharp.Collections // windowed : int -> seq<'T> -> seq<'T[]> [] let windowed windowSize (source: seq<_>) = - if windowSize <= 0 then invalidArgFmt "windowSize" "{0}\nwindowSize = {1}" - [|SR.GetString SR.inputMustBePositive; windowSize|] source |> toComposer |> Composer.windowed windowSize |> Upcast.enumerable [] diff --git a/src/fsharp/FSharp.Core/seqcomposer.fs b/src/fsharp/FSharp.Core/seqcomposer.fs index 0026fa3a2b8..213a59ee47f 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fs +++ b/src/fsharp/FSharp.Core/seqcomposer.fs @@ -840,6 +840,7 @@ namespace Microsoft.FSharp.Collections [] let ofArray (source:array<'T>) : ISeq<'T> = + checkNonNull "source" source Upcast.seq (Array.Enumerable (source, IdentityFactory.Instance, 1)) [] @@ -1514,6 +1515,9 @@ namespace Microsoft.FSharp.Collections [] let windowed (windowSize:int) (source:ISeq<'T>) : ISeq<'T[]> = + if windowSize <= 0 then + invalidArgFmt "windowSize" "{0}\nwindowSize = {1}" [|SR.GetString SR.inputMustBePositive; windowSize|] + source.PushTransform { new TransformFactory<'T,'T[]>() with member __.Compose outOfBand pipeIdx next = upcast { @@ -1630,54 +1634,52 @@ namespace Microsoft.FSharp.Collections let inline countByRef<'T,'Key when 'Key : equality and 'Key : not struct> (projection:'T -> 'Key) (source:ISeq<'T>) = CountBy.byRef projection source + [] + let length (source:ISeq<'T>) = + source.Fold (fun _ -> + upcast { new Folder<'T,int,NoValue>(0,Unchecked.defaultof<_>) with + override this.ProcessNext v = + this.Result <- this.Result + 1 + Unchecked.defaultof<_> (* return value unused in Fold context *) }) + [] let toArray (source:ISeq<'T>) = - match box source with - | :? ('T[]) as res -> (res.Clone() :?> 'T[]) - | :? ('T list) as res -> List.toArray res - | :? ICollection<'T> as res -> - // Directly create an array and copy ourselves. - // This avoids an extra copy if using ResizeArray in fallback below. - let arr = Array.zeroCreateUnchecked res.Count - res.CopyTo(arr, 0) - arr - | _ -> - source.Fold (fun _ -> - upcast { new FolderWithPostProcessing<'T,array<'T>,_>(Unchecked.defaultof<_>,ResizeArray ()) with - override this.ProcessNext v = - this.State.Add v - Unchecked.defaultof<_> (* return value unused in Fold context *) - override this.OnComplete _ = - this.Result <- this.State.ToArray () - override this.OnDispose () = () }) + source.Fold (fun _ -> + upcast { new FolderWithPostProcessing<'T,array<'T>,_>(Unchecked.defaultof<_>,ResizeArray ()) with + override this.ProcessNext v = + this.State.Add v + Unchecked.defaultof<_> (* return value unused in Fold context *) + override this.OnComplete _ = + this.Result <- this.State.ToArray () + override this.OnDispose () = () }) [] let sortBy keyf source = delay (fun () -> let array = source |> toArray Array.stableSortInPlaceBy keyf array - Upcast.seq (Array.Enumerable (array, IdentityFactory.Instance, 1))) + ofArray array) [] let sort source = delay (fun () -> let array = source |> toArray Array.stableSortInPlace array - Upcast.seq (Array.Enumerable (array, IdentityFactory.Instance, 1))) + ofArray array) [] let sortWith f source = delay (fun () -> let array = source |> toArray Array.stableSortInPlaceWith f array - Upcast.seq (Array.Enumerable (array, IdentityFactory.Instance, 1))) + ofArray array) [] let rev source = delay (fun () -> let array = source |> toArray Array.Reverse array - Upcast.seq (Array.Enumerable (array, IdentityFactory.Instance, 1))) + ofArray array) [] let permute f (source:ISeq<_>) = @@ -1685,4 +1687,39 @@ namespace Microsoft.FSharp.Collections source |> toArray |> Array.permute f - |> fun array -> Upcast.seq (Array.Enumerable (array, IdentityFactory.Instance, 1))) + |> ofArray) + + [] + let scanBack<'T,'State> f (source:ISeq<'T>) (acc:'State) : ISeq<'State> = + delay (fun () -> + let array = source |> toArray + Array.scanSubRight f array 0 (array.Length - 1) acc + |> ofArray) + + let inline foldArraySubRight f (arr: 'T[]) start fin acc = + let mutable state = acc + for i = fin downto start do + state <- f arr.[i] state + state + + [] + let inline foldBack<'T,'State> f (source: ISeq<'T>) (x:'State) = + let arr = toArray source + let len = arr.Length + foldArraySubRight f arr 0 (len - 1) x + + [] + let zip source1 source2 = + map2 (fun x y -> x,y) source1 source2 + + [] + let inline foldBack2<'T1,'T2,'State> f (source1:ISeq<'T1>) (source2:ISeq<'T2>) (x:'State) = + let zipped = zip source1 source2 + foldBack ((<||) f) zipped x + + [] + let inline reduceBack f (source:ISeq<'T>) = + let arr = toArray source + match arr.Length with + | 0 -> invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + | len -> foldArraySubRight f arr 0 (len - 2) arr.[len - 1] diff --git a/src/fsharp/FSharp.Core/seqcomposer.fsi b/src/fsharp/FSharp.Core/seqcomposer.fsi index 1df1b9ee772..22d4cc05142 100644 --- a/src/fsharp/FSharp.Core/seqcomposer.fsi +++ b/src/fsharp/FSharp.Core/seqcomposer.fsi @@ -317,6 +317,9 @@ namespace Microsoft.FSharp.Collections [] val inline countByRef : projection:('T -> 'Key) -> source:ISeq<'T> -> ISeq<'Key * int> when 'Key : equality and 'Key : not struct + [] + val length: source:ISeq<'T> -> int + [] val toArray: source:ISeq<'T> -> array<'T> @@ -335,6 +338,21 @@ namespace Microsoft.FSharp.Collections [] val permute: indexMap:(int->int) -> source:ISeq<'T> -> ISeq<'T> + [] + val scanBack<'T,'State> : folder:('T->'State->'State) -> source:ISeq<'T> -> state:'State -> ISeq<'State> + + [] + val zip: source1:ISeq<'T1> -> source2:ISeq<'T2> -> ISeq<'T1 * 'T2> + + [] + val inline reduceBack: reduction:('T->'T->'T) -> source:ISeq<'T> -> 'T + + [] + val inline foldBack<'T,'State> : folder:('T->'State->'State) -> source:ISeq<'T> -> state:'State -> 'State + + [] + val inline foldBack2<'T1,'T2,'State> : folder:('T1->'T2->'State->'State) -> source1:ISeq<'T1> -> source2:ISeq<'T2> -> state:'State -> 'State + module internal GroupBy = val inline byVal : projection:('T -> 'Key) -> source:ISeq<'T> -> ISeq<'Key * ISeq<'T>> when 'Key : equality val inline byRef : projection:('T -> 'Key) -> source:ISeq<'T> -> ISeq<'Key * ISeq<'T>> when 'Key : equality From cecb26e13081cf2331da3d954b8187a41494ad1f Mon Sep 17 00:00:00 2001 From: Jared Hester Date: Mon, 6 Mar 2017 18:24:51 -0500 Subject: [PATCH 59/59] adjust seq tests for better filering and sorting --- .../CollectionModulesConsistency.fs | 5 +- .../Microsoft.FSharp.Collections/SeqModule.fs | 76 ++++---- .../SeqModule2.fs | 170 +++++++++--------- .../SeqProperties.fs | 5 +- 4 files changed, 132 insertions(+), 124 deletions(-) diff --git a/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs index 766e33fb07b..5453dd6f529 100644 --- a/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs +++ b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs @@ -1,5 +1,8 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - +[] +[] +[] +[] module FSharp.Core.Unittests.FSharp_Core.Microsoft_FSharp_Collections.CollectionModulesConsistency open System diff --git a/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs index ba61fdcf95f..f7e12fdfd3b 100644 --- a/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs +++ b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs @@ -19,11 +19,11 @@ Make sure each method works on: * Null Seq (null) *) -[] -type SeqModule() = +[][][] +module SeqModuleTests = [] - member this.AllPairs() = + let AllPairs() = // integer Seq let resultInt = Seq.allPairs (seq [1..7]) (seq [11..17]) @@ -50,7 +50,7 @@ type SeqModule() = () [] - member this.CachedSeq_Clear() = + let CachedSeq_Clear() = let evaluatedItems : int list ref = ref [] let cachedSeq = @@ -90,7 +90,7 @@ type SeqModule() = () [] - member this.Append() = + let Append() = // empty Seq let emptySeq1 = Seq.empty @@ -135,7 +135,7 @@ type SeqModule() = () [] - member this.replicate() = + let replicate() = // replicate should create multiple copies of the given value Assert.IsTrue(Seq.isEmpty <| Seq.replicate 0 null) Assert.IsTrue(Seq.isEmpty <| Seq.replicate 0 1) @@ -146,7 +146,7 @@ type SeqModule() = [] - member this.Average() = + let Average() = // empty Seq let emptySeq:seq = Seq.empty @@ -182,7 +182,7 @@ type SeqModule() = [] - member this.AverageBy() = + let AverageBy() = // empty Seq let emptySeq:seq = Seq.empty @@ -216,7 +216,7 @@ type SeqModule() = () [] - member this.Cache() = + let Cache() = // empty Seq let emptySeq:seq = Seq.empty @@ -257,7 +257,7 @@ type SeqModule() = () [] - member this.Case() = + let Case() = // integer Seq let integerArray = [|1;2|] @@ -304,7 +304,7 @@ type SeqModule() = () [] - member this.Choose() = + let Choose() = // int Seq let intSeq = seq [1..20] @@ -343,7 +343,7 @@ type SeqModule() = () [] - member this.ChunkBySize() = + let ChunkBySize() = let verify expected actual = Seq.zip expected actual @@ -379,7 +379,7 @@ type SeqModule() = () [] - member this.SplitInto() = + let SplitInto() = let verify expected actual = Seq.zip expected actual @@ -410,7 +410,7 @@ type SeqModule() = () [] - member this.Compare() = + let Compare() = // int Seq let intSeq1 = seq [1;3;7;9] @@ -446,7 +446,7 @@ type SeqModule() = () [] - member this.Concat() = + let Concat() = // integer Seq let seqInt = seq { for i in 0..9 do @@ -482,7 +482,7 @@ type SeqModule() = () [] - member this.CountBy() = + let CountBy() = // integer Seq let funcIntCount_by (x:int) = x%3 let seqInt = @@ -516,7 +516,7 @@ type SeqModule() = () [] - member this.Distinct() = + let Distinct() = // integer Seq let IntDistinctSeq = @@ -550,7 +550,7 @@ type SeqModule() = () [] - member this.DistinctBy () = + let DistinctBy () = // integer Seq let funcInt x = x % 3 let IntDistinct_bySeq = @@ -585,7 +585,7 @@ type SeqModule() = () [] - member this.Except() = + let Except() = // integer Seq let intSeq1 = seq { yield! {1..100} yield! {1..100} } @@ -624,7 +624,7 @@ type SeqModule() = () [] - member this.Exists() = + let Exists() = // Integer Seq let funcInt x = (x % 2 = 0) @@ -659,7 +659,7 @@ type SeqModule() = () [] - member this.Exists2() = + let Exists2() = // Integer Seq let funcInt x y = (x+y)%3=0 let Intexists2Seq1 = seq [1;3;7] @@ -687,7 +687,7 @@ type SeqModule() = [] - member this.Filter() = + let Filter() = // integer Seq let funcInt x = if (x % 5 = 0) then true else false let IntSeq = @@ -726,7 +726,7 @@ type SeqModule() = () [] - member this.Find() = + let Find() = // integer Seq let funcInt x = if (x % 5 = 0) then true else false @@ -755,7 +755,7 @@ type SeqModule() = () [] - member this.FindBack() = + let FindBack() = // integer Seq let funcInt x = x % 5 = 0 Assert.AreEqual(20, Seq.findBack funcInt <| seq { 1..20 }) @@ -782,7 +782,7 @@ type SeqModule() = () [] - member this.FindIndex() = + let FindIndex() = // integer Seq let digits = [1 .. 100] |> Seq.ofList @@ -797,7 +797,7 @@ type SeqModule() = () [] - member this.Permute() = + let Permute() = let mapIndex i = (i + 1) % 4 // integer seq @@ -823,7 +823,7 @@ type SeqModule() = () [] - member this.FindIndexBack() = + let FindIndexBack() = // integer Seq let digits = seq { 1..100 } let idx = digits |> Seq.findIndexBack (fun i -> i.ToString().Length = 1) @@ -843,7 +843,7 @@ type SeqModule() = () [] - member this.Pick() = + let Pick() = let digits = [| 1 .. 10 |] |> Seq.ofArray let result = Seq.pick (fun i -> if i > 5 then Some(i.ToString()) else None) digits @@ -857,7 +857,7 @@ type SeqModule() = () [] - member this.Fold() = + let Fold() = let funcInt x y = x+y let IntSeq = @@ -889,7 +889,7 @@ type SeqModule() = [] - member this.Fold2() = + let Fold2() = Assert.AreEqual([(3,5); (2,3); (1,1)],Seq.fold2 (fun acc x y -> (x,y)::acc) [] (seq [ 1..3 ]) (seq [1..2..6])) // integer List @@ -921,7 +921,7 @@ type SeqModule() = () [] - member this.FoldBack() = + let FoldBack() = // int Seq let funcInt x y = x-y let IntSeq = seq { 1..4 } @@ -957,7 +957,7 @@ type SeqModule() = () [] - member this.foldBack2() = + let foldBack2() = // int Seq let funcInt x y z = x + y + z let intSeq = seq { 1..10 } @@ -996,7 +996,7 @@ type SeqModule() = () [] - member this.ForAll() = + let ForAll() = let funcInt x = if x%2 = 0 then true else false let IntSeq = @@ -1027,7 +1027,7 @@ type SeqModule() = () [] - member this.ForAll2() = + let ForAll2() = let funcInt x y = if (x+y)%2 = 0 then true else false let IntSeq = @@ -1058,7 +1058,7 @@ type SeqModule() = CheckThrowsArgumentNullException (fun () -> Seq.forall2 funcInt nullSeq nullSeq |> ignore) [] - member this.GroupBy() = + let GroupBy() = let funcInt x = x%5 @@ -1101,7 +1101,7 @@ type SeqModule() = () [] - member this.DisposalOfUnstartedEnumerator() = + let DisposalOfUnstartedEnumerator() = let run = ref false let f() = seq { try @@ -1114,7 +1114,7 @@ type SeqModule() = Assert.IsFalse(!run) [] - member this.WeirdLocalNames() = + let WeirdLocalNames() = let f pc = seq { yield pc @@ -1135,7 +1135,7 @@ type SeqModule() = Assert.AreEqual([6;7;8], l) [] - member this.Contains() = + let Contains() = // Integer Seq let intSeq = seq { 0..9 } diff --git a/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs index 0645069b4f9..744ce00466f 100644 --- a/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs +++ b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule2.fs @@ -15,11 +15,13 @@ type SeqWindowedTestInput<'t> = Exception : Type option } + +[][][] [] -type SeqModule2() = +module SeqModule2 = [] - member this.Hd() = + let Hd() = let IntSeq = seq { for i in 0 .. 9 do @@ -41,7 +43,7 @@ type SeqModule2() = () [] - member this.TryHead() = + let TryHead() = // int Seq let IntSeq = seq { for i in 0 .. 9 -> i } @@ -62,7 +64,7 @@ type SeqModule2() = () [] - member this.Tl() = + let Tl() = // integer seq let resultInt = Seq.tail <| seq { 1..10 } Assert.AreEqual(Array.ofSeq (seq { 2..10 }), Array.ofSeq resultInt) @@ -80,7 +82,7 @@ type SeqModule2() = () [] - member this.Last() = + let Last() = let IntSeq = seq { for i in 0 .. 9 do @@ -102,7 +104,7 @@ type SeqModule2() = () [] - member this.TryLast() = + let TryLast() = let IntSeq = seq { for i in 0 .. 9 -> i } @@ -124,7 +126,7 @@ type SeqModule2() = () [] - member this.ExactlyOne() = + let ExactlyOne() = let IntSeq = seq { for i in 7 .. 7 do @@ -151,7 +153,7 @@ type SeqModule2() = [] - member this.Init() = + let Init() = let funcInt x = x let init_finiteInt = Seq.init 9 funcInt @@ -176,7 +178,7 @@ type SeqModule2() = () [] - member this.InitInfinite() = + let InitInfinite() = let funcInt x = x let init_infiniteInt = Seq.initInfinite funcInt @@ -194,7 +196,7 @@ type SeqModule2() = [] - member this.IsEmpty() = + let IsEmpty() = //seq int let seqint = seq [1;2;3] @@ -219,7 +221,7 @@ type SeqModule2() = () [] - member this.Iter() = + let Iter() = //seq int let seqint = seq [ 1..3] let cacheint = ref 0 @@ -248,7 +250,7 @@ type SeqModule2() = () [] - member this.Iter2() = + let Iter2() = //seq int let seqint = seq [ 1..3] @@ -278,7 +280,7 @@ type SeqModule2() = () [] - member this.Iteri() = + let Iteri() = // seq int let seqint = seq [ 1..10] @@ -308,7 +310,7 @@ type SeqModule2() = () [] - member this.Iteri2() = + let Iteri2() = //seq int let seqint = seq [ 1..3] @@ -351,7 +353,7 @@ type SeqModule2() = () [] - member this.Length() = + let Length() = // integer seq let resultInt = Seq.length {1..8} @@ -372,7 +374,7 @@ type SeqModule2() = () [] - member this.Map() = + let Map() = // integer Seq let funcInt x = @@ -403,7 +405,7 @@ type SeqModule2() = () [] - member this.Map2() = + let Map2() = // integer Seq let funcInt x y = x+y let resultInt = Seq.map2 funcInt { 1..10 } {2..2..20} @@ -430,7 +432,7 @@ type SeqModule2() = () [] - member this.Map3() = + let Map3() = // Integer seq let funcInt a b c = (a + b) * c let resultInt = Seq.map3 funcInt { 1..8 } { 2..9 } { 3..10 } @@ -462,7 +464,7 @@ type SeqModule2() = () [] - member this.MapFold() = + let MapFold() = // integer Seq let funcInt acc x = if x % 2 = 0 then 10*x, acc + 1 else x, acc let resultInt,resultIntAcc = Seq.mapFold funcInt 100 <| seq { 1..10 } @@ -487,7 +489,7 @@ type SeqModule2() = () [] - member this.MapFoldBack() = + let MapFoldBack() = // integer Seq let funcInt x acc = if acc < 105 then 10*x, acc + 2 else x, acc let resultInt,resultIntAcc = Seq.mapFoldBack funcInt (seq { 1..10 }) 100 @@ -511,7 +513,7 @@ type SeqModule2() = () - member private this.MapWithSideEffectsTester (map : (int -> int) -> seq -> seq) expectExceptions = + let private MapWithSideEffectsTester (map : (int -> int) -> seq -> seq) expectExceptions = let i = ref 0 let f x = i := !i + 1; x*x let e = ([1;2] |> map f).GetEnumerator() @@ -548,7 +550,7 @@ type SeqModule2() = Assert.AreEqual(0,!i) - member private this.MapWithExceptionTester (map : (int -> int) -> seq -> seq) = + let private MapWithExceptionTester (map : (int -> int) -> seq -> seq) = let raiser x = if x > 0 then raise(NotSupportedException()) else x let e = (map raiser [0; 1]).GetEnumerator() Assert.IsTrue(e.MoveNext()) // should not throw @@ -557,34 +559,34 @@ type SeqModule2() = Assert.AreEqual(0, e.Current) // should not throw [] - member this.MapWithSideEffects () = - this.MapWithSideEffectsTester Seq.map true + let MapWithSideEffects () = + MapWithSideEffectsTester Seq.map true [] - member this.MapWithException () = - this.MapWithExceptionTester Seq.map + let MapWithException () = + MapWithExceptionTester Seq.map [] - member this.SingletonCollectWithSideEffects () = - this.MapWithSideEffectsTester (fun f-> Seq.collect (f >> Seq.singleton)) true + let SingletonCollectWithSideEffects () = + MapWithSideEffectsTester (fun f-> Seq.collect (f >> Seq.singleton)) true [] - member this.SingletonCollectWithException () = - this.MapWithExceptionTester (fun f-> Seq.collect (f >> Seq.singleton)) + let SingletonCollectWithException () = + MapWithExceptionTester (fun f-> Seq.collect (f >> Seq.singleton)) #if !FX_NO_LINQ [] - member this.SystemLinqSelectWithSideEffects () = - this.MapWithSideEffectsTester (fun f s -> System.Linq.Enumerable.Select(s, Func<_,_>(f))) false + let SystemLinqSelectWithSideEffects () = + MapWithSideEffectsTester (fun f s -> System.Linq.Enumerable.Select(s, Func<_,_>(f))) false [] - member this.SystemLinqSelectWithException () = - this.MapWithExceptionTester (fun f s -> System.Linq.Enumerable.Select(s, Func<_,_>(f))) + let SystemLinqSelectWithException () = + MapWithExceptionTester (fun f s -> System.Linq.Enumerable.Select(s, Func<_,_>(f))) #endif [] - member this.MapiWithSideEffects () = + let MapiWithSideEffects () = let i = ref 0 let f _ x = i := !i + 1; x*x let e = ([1;2] |> Seq.mapi f).GetEnumerator() @@ -618,7 +620,7 @@ type SeqModule2() = Assert.AreEqual(0,!i) [] - member this.Map2WithSideEffects () = + let Map2WithSideEffects () = let i = ref 0 let f x y = i := !i + 1; x*x let e = (Seq.map2 f [1;2] [1;2]).GetEnumerator() @@ -652,7 +654,7 @@ type SeqModule2() = Assert.AreEqual(0,!i) [] - member this.Mapi2WithSideEffects () = + let Mapi2WithSideEffects () = let i = ref 0 let f _ x y = i := !i + 1; x*x let e = (Seq.mapi2 f [1;2] [1;2]).GetEnumerator() @@ -686,7 +688,7 @@ type SeqModule2() = Assert.AreEqual(0,!i) [] - member this.Collect() = + let Collect() = // integer Seq let funcInt x = seq [x+1] let resultInt = Seq.collect funcInt { 1..10 } @@ -718,7 +720,7 @@ type SeqModule2() = () [] - member this.Mapi() = + let Mapi() = // integer Seq let funcInt x y = x+y @@ -747,7 +749,7 @@ type SeqModule2() = () [] - member this.Mapi2() = + let Mapi2() = // integer Seq let funcInt x y z = x+y+z let resultInt = Seq.mapi2 funcInt { 1..10 } {2..2..20} @@ -783,7 +785,7 @@ type SeqModule2() = VerifySeqsEqual (seq [3;6;9;12;15;18;21;24;27;30]) (testSeqLengths longerSeq shorterSeq) [] - member this.Indexed() = + let Indexed() = // integer Seq let resultInt = Seq.indexed { 10..2..20 } @@ -808,7 +810,7 @@ type SeqModule2() = () [] - member this.Max() = + let Max() = // integer Seq let resultInt = Seq.max { 10..20 } @@ -829,7 +831,7 @@ type SeqModule2() = () [] - member this.MaxBy() = + let MaxBy() = // integer Seq let funcInt x = x % 8 @@ -851,7 +853,7 @@ type SeqModule2() = () [] - member this.MinBy() = + let MinBy() = // integer Seq let funcInt x = x % 8 @@ -874,7 +876,7 @@ type SeqModule2() = [] - member this.Min() = + let Min() = // integer Seq let resultInt = Seq.min { 10..20 } @@ -894,7 +896,7 @@ type SeqModule2() = () [] - member this.Item() = + let Item() = // integer Seq let resultInt = Seq.item 3 { 10..20 } Assert.AreEqual(13, resultInt) @@ -919,7 +921,7 @@ type SeqModule2() = CheckThrowsArgumentException (fun () -> Seq.item i { 10 .. 20 } |> ignore) [] - member this.``item should fail with correct number of missing elements``() = + let ``item should fail with correct number of missing elements``() = try Seq.item 0 (Array.zeroCreate 0) |> ignore failwith "error expected" @@ -933,7 +935,7 @@ type SeqModule2() = | exn when exn.Message.Contains("seq was short by 3 elements") -> () [] - member this.Of_Array() = + let Of_Array() = // integer Seq let resultInt = Seq.ofArray [|1..10|] let expectedInt = {1..10} @@ -952,7 +954,7 @@ type SeqModule2() = () [] - member this.Of_List() = + let Of_List() = // integer Seq let resultInt = Seq.ofList [1..10] let expectedInt = {1..10} @@ -972,7 +974,7 @@ type SeqModule2() = [] - member this.Pairwise() = + let Pairwise() = // integer Seq let resultInt = Seq.pairwise {1..3} @@ -992,7 +994,7 @@ type SeqModule2() = () [] - member this.Reduce() = + let Reduce() = // integer Seq let resultInt = Seq.reduce (fun x y -> x/y) (seq [5*4*3*2; 4;3;2;1]) @@ -1011,7 +1013,7 @@ type SeqModule2() = () [] - member this.ReduceBack() = + let ReduceBack() = // int Seq let funcInt x y = x - y let IntSeq = seq { 1..4 } @@ -1040,7 +1042,7 @@ type SeqModule2() = () [] - member this.Rev() = + let Rev() = // integer Seq let resultInt = Seq.rev (seq [5;4;3;2;1]) VerifySeqsEqual (seq[1;2;3;4;5]) resultInt @@ -1058,7 +1060,7 @@ type SeqModule2() = () [] - member this.Scan() = + let Scan() = // integer Seq let funcInt x y = x+y let resultInt = Seq.scan funcInt 9 {1..10} @@ -1083,7 +1085,7 @@ type SeqModule2() = () [] - member this.ScanBack() = + let ScanBack() = // integer Seq let funcInt x y = x+y let resultInt = Seq.scanBack funcInt { 1..10 } 9 @@ -1123,7 +1125,7 @@ type SeqModule2() = () [] - member this.Singleton() = + let Singleton() = // integer Seq let resultInt = Seq.singleton 1 @@ -1143,7 +1145,7 @@ type SeqModule2() = [] - member this.Skip() = + let Skip() = // integer Seq let resultInt = Seq.skip 2 (seq [1;2;3;4]) @@ -1165,7 +1167,7 @@ type SeqModule2() = () [] - member this.Skip_While() = + let Skip_While() = // integer Seq let funcInt x = (x < 3) @@ -1188,7 +1190,7 @@ type SeqModule2() = () [] - member this.Sort() = + let Sort() = // integer Seq let resultInt = Seq.sort (seq [1;3;2;4;6;5;7]) @@ -1210,7 +1212,7 @@ type SeqModule2() = () [] - member this.SortBy() = + let SortBy() = // integer Seq let funcInt x = Math.Abs(x-5) @@ -1234,7 +1236,7 @@ type SeqModule2() = () [] - member this.SortDescending() = + let SortDescending() = // integer Seq let resultInt = Seq.sortDescending (seq [1;3;2;Int32.MaxValue;4;6;Int32.MinValue;5;7;0]) @@ -1273,7 +1275,7 @@ type SeqModule2() = () [] - member this.SortByDescending() = + let SortByDescending() = // integer Seq let funcInt x = Math.Abs(x-5) @@ -1309,7 +1311,7 @@ type SeqModule2() = CheckThrowsArgumentNullException(fun() -> Seq.sortByDescending funcInt null |> ignore) () - member this.SortWith() = + let SortWith() = // integer Seq let intComparer a b = compare (a%3) (b%3) @@ -1332,7 +1334,7 @@ type SeqModule2() = () [] - member this.Sum() = + let Sum() = // integer Seq let resultInt = Seq.sum (seq [1..10]) @@ -1372,7 +1374,7 @@ type SeqModule2() = () [] - member this.SumBy() = + let SumBy() = // integer Seq let resultInt = Seq.sumBy int (seq [1..10]) @@ -1411,7 +1413,7 @@ type SeqModule2() = () [] - member this.Take() = + let Take() = // integer Seq let resultInt = Seq.take 3 (seq [1;2;4;5;7]) @@ -1437,7 +1439,7 @@ type SeqModule2() = () [] - member this.takeWhile() = + let takeWhile() = // integer Seq let funcInt x = (x < 6) let resultInt = Seq.takeWhile funcInt (seq [1;2;4;5;6;7]) @@ -1461,7 +1463,7 @@ type SeqModule2() = () [] - member this.ToArray() = + let ToArray() = // integer Seq let resultInt = Seq.toArray(seq [1;2;4;5;7]) @@ -1483,32 +1485,32 @@ type SeqModule2() = () [] - member this.ToArrayFromICollection() = + let ToArrayFromICollection() = let inputCollection = ResizeArray(seq [1;2;4;5;7]) let resultInt = Seq.toArray(inputCollection) let expectedInt = [|1;2;4;5;7|] Assert.AreEqual(expectedInt,resultInt) [] - member this.ToArrayEmptyInput() = + let ToArrayEmptyInput() = let resultInt = Seq.toArray(Seq.empty) let expectedInt = Array.empty Assert.AreEqual(expectedInt,resultInt) [] - member this.ToArrayFromArray() = + let ToArrayFromArray() = let resultInt = Seq.toArray([|1;2;4;5;7|]) let expectedInt = [|1;2;4;5;7|] Assert.AreEqual(expectedInt,resultInt) [] - member this.ToArrayFromList() = + let ToArrayFromList() = let resultInt = Seq.toArray([1;2;4;5;7]) let expectedInt = [|1;2;4;5;7|] Assert.AreEqual(expectedInt,resultInt) [] - member this.ToList() = + let ToList() = // integer Seq let resultInt = Seq.toList (seq [1;2;4;5;7]) let expectedInt = [1;2;4;5;7] @@ -1528,7 +1530,7 @@ type SeqModule2() = () [] - member this.Truncate() = + let Truncate() = // integer Seq let resultInt = Seq.truncate 3 (seq [1;2;4;5;7]) let expectedInt = [1;2;4] @@ -1553,7 +1555,7 @@ type SeqModule2() = () [] - member this.tryFind() = + let tryFind() = // integer Seq let resultInt = Seq.tryFind (fun x -> (x%2=0)) (seq [1;2;4;5;7]) Assert.AreEqual(Some(2), resultInt) @@ -1580,7 +1582,7 @@ type SeqModule2() = () [] - member this.TryFindBack() = + let TryFindBack() = // integer Seq let resultInt = Seq.tryFindBack (fun x -> (x%2=0)) (seq [1;2;4;5;7]) Assert.AreEqual(Some 4, resultInt) @@ -1606,7 +1608,7 @@ type SeqModule2() = () [] - member this.TryFindIndex() = + let TryFindIndex() = // integer Seq let resultInt = Seq.tryFindIndex (fun x -> (x % 5 = 0)) [8; 9; 10] @@ -1634,7 +1636,7 @@ type SeqModule2() = () [] - member this.TryFindIndexBack() = + let TryFindIndexBack() = // integer Seq let resultInt = Seq.tryFindIndexBack (fun x -> (x % 5 = 0)) [5; 9; 10; 12] @@ -1661,7 +1663,7 @@ type SeqModule2() = () [] - member this.Unfold() = + let Unfold() = // integer Seq let resultInt = Seq.unfold (fun x -> if x = 1 then Some(7,2) else None) 1 @@ -1675,7 +1677,7 @@ type SeqModule2() = [] - member this.Windowed() = + let Windowed() = let testWindowed config = try @@ -1739,7 +1741,7 @@ type SeqModule2() = () [] - member this.Zip() = + let Zip() = // integer Seq let resultInt = Seq.zip (seq [1..7]) (seq [11..17]) @@ -1764,7 +1766,7 @@ type SeqModule2() = () [] - member this.Zip3() = + let Zip3() = // integer Seq let resultInt = Seq.zip3 (seq [1..7]) (seq [11..17]) (seq [21..27]) let expectedInt = @@ -1789,7 +1791,7 @@ type SeqModule2() = () [] - member this.tryPick() = + let tryPick() = // integer Seq let resultInt = Seq.tryPick (fun x-> if x = 1 then Some("got") else None) (seq [1..5]) @@ -1812,7 +1814,7 @@ type SeqModule2() = () [] - member this.tryItem() = + let tryItem() = // integer Seq let resultInt = Seq.tryItem 3 { 10..20 } Assert.AreEqual(Some(13), resultInt) diff --git a/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/SeqProperties.fs b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/SeqProperties.fs index f5ccc34a171..1f2f599ec3c 100644 --- a/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/SeqProperties.fs +++ b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Collections/SeqProperties.fs @@ -1,5 +1,8 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - +[] +[] +[] +[] module FSharp.Core.Unittests.FSharp_Core.Microsoft_FSharp_Collections.SeqProperties open System