Skip to content

Commit

Permalink
Merge pull request dotnet#16 from liboz/manofstick
Browse files Browse the repository at this point in the history
Seq.iteri, exists, contains, forall, trypick, pick, tryfind, find, re…
  • Loading branch information
manofstick authored Oct 20, 2016
2 parents b1a4884 + b2e1302 commit de6e4e8
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 109 deletions.
240 changes: 141 additions & 99 deletions src/fsharp/FSharp.Core/seq.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1476,6 +1476,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)))

[<CompiledName("ToComposer")>]
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

[<CompiledName("Delay")>]
let delay f = mkDelayedSeq f
Expand All @@ -1499,17 +1510,13 @@ namespace Microsoft.FSharp.Collections

[<CompiledName("Iterate")>]
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

[<CompiledName("Item")>]
let item i (source : seq<'T>) =
Expand All @@ -1530,41 +1537,69 @@ namespace Microsoft.FSharp.Collections

[<CompiledName("IterateIndexed")>]
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

[<CompiledName("Exists")>]
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

[<CompiledName("Contains")>]
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

[<CompiledName("ForAll")>]
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

[<CompiledName("Iterate2")>]
let iter2 f (source1 : seq<_>) (source2 : seq<_>) =
Expand Down Expand Up @@ -1659,33 +1694,47 @@ namespace Microsoft.FSharp.Collections

[<CompiledName("TryPick")>]
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

[<CompiledName("Pick")>]
let pick f source =
checkNonNull "source" source
match tryPick f source with
| None -> indexNotFound()
| Some x -> x

[<CompiledName("TryFind")>]
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

[<CompiledName("Find")>]
let find f source =
checkNonNull "source" source
match tryFind f source with
| None -> indexNotFound()
| Some x -> x
Expand Down Expand Up @@ -1730,24 +1779,15 @@ namespace Microsoft.FSharp.Collections

[<CompiledName("Fold")>]
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

[<CompiledName("Fold2")>]
let fold2<'T1,'T2,'State> f (state:'State) (source1: seq<'T1>) (source2: seq<'T2>) =
Expand All @@ -1767,14 +1807,25 @@ namespace Microsoft.FSharp.Collections

[<CompiledName("Reduce")>]
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

[<CompiledName("Replicate")>]
let replicate count x =
Expand Down Expand Up @@ -2174,17 +2225,6 @@ namespace Microsoft.FSharp.Collections
then mkDelayedSeq (fun () -> countByValueType keyf source)
else mkDelayedSeq (fun () -> countByRefType keyf source)

[<CompiledName("ToComposer")>]
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

[<CompiledName("Sum")>]
let inline sum (source:seq<'a>) : 'a =
let composedSource = toComposer source
Expand Down Expand Up @@ -2432,28 +2472,30 @@ namespace Microsoft.FSharp.Collections
[<CompiledName("Tail")>]
let tail (source: seq<'T>) =
source |> seqFactory (SeqComposer.TailFactory ())

[<CompiledName("Last")>]
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


[<CompiledName("TryLast")>]
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)

[<CompiledName("Last")>]
let last (source : seq<_>) =
match tryLast source with
| None -> invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
| Some x -> x

[<CompiledName("ExactlyOne")>]
let exactlyOne (source : seq<_>) =
Expand Down
20 changes: 10 additions & 10 deletions src/fsharp/FSharp.Core/seq.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -1155,16 +1155,6 @@ namespace Microsoft.FSharp.Collections
[<CompiledName("SortByDescending")>]
val inline sortByDescending : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> when 'Key : comparison

/// <summary>Builds an SeqEnumerable from the given collection.</summary>
///
/// <param name="source">The input sequence.</param>
///
/// <returns>The result SeqEnumerable.</returns>
///
/// <exception cref="System.ArgumentNullException">Thrown when the input sequence is null.</exception>
[<CompiledName("ToComposer")>]
val toComposer : source:seq<'T> -> SeqComposer.SeqEnumerable<'T>

/// <summary>Returns the sum of the elements in the sequence.</summary>
///
/// <remarks>The elements are summed using the <c>+</c> operator and <c>Zero</c> property associated with the generated type.</remarks>
Expand Down Expand Up @@ -1239,6 +1229,16 @@ namespace Microsoft.FSharp.Collections
/// <exception cref="System.ArgumentNullException">Thrown when the input sequence is null.</exception>
[<CompiledName("ToArray")>]
val toArray: source:seq<'T> -> 'T[]

/// <summary>Builds an SeqEnumerable from the given collection.</summary>
///
/// <param name="source">The input sequence.</param>
///
/// <returns>The result SeqEnumerable.</returns>
///
/// <exception cref="System.ArgumentNullException">Thrown when the input sequence is null.</exception>
[<CompiledName("ToComposer")>]
val toComposer : source:seq<'T> -> SeqComposer.SeqEnumerable<'T>

/// <summary>Builds a list from the given collection.</summary>
///
Expand Down

0 comments on commit de6e4e8

Please sign in to comment.