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>
-
///