Skip to content

Commit 56f4dbe

Browse files
committed
Also simplify skipWhile and skipWhileInclusive (plus async variants)
1 parent 4ed6ba5 commit 56f4dbe

File tree

2 files changed

+32
-46
lines changed

2 files changed

+32
-46
lines changed

src/FSharp.Control.TaskSeq/TaskSeq.fs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,10 @@ type TaskSeq private () =
303303
static member takeWhileAsync predicate source = Internal.takeWhile false (PredicateAsync predicate) source
304304
static member takeWhileInclusive predicate source = Internal.takeWhile true (Predicate predicate) source
305305
static member takeWhileInclusiveAsync predicate source = Internal.takeWhile true (PredicateAsync predicate) source
306-
static member skipWhile predicate source = Internal.skipWhile Exclusive (Predicate predicate) source
307-
static member skipWhileAsync predicate source = Internal.skipWhile Exclusive (PredicateAsync predicate) source
308-
static member skipWhileInclusive predicate source = Internal.skipWhile Inclusive (Predicate predicate) source
309-
static member skipWhileInclusiveAsync predicate source = Internal.skipWhile Inclusive (PredicateAsync predicate) source
306+
static member skipWhile predicate source = Internal.skipWhile false (Predicate predicate) source
307+
static member skipWhileAsync predicate source = Internal.skipWhile false (PredicateAsync predicate) source
308+
static member skipWhileInclusive predicate source = Internal.skipWhile true (Predicate predicate) source
309+
static member skipWhileInclusiveAsync predicate source = Internal.skipWhile true (PredicateAsync predicate) source
310310

311311
static member tryPick chooser source = Internal.tryPick (TryPick chooser) source
312312
static member tryPickAsync chooser source = Internal.tryPick (TryPickAsync chooser) source

src/FSharp.Control.TaskSeq/TaskSeqInternal.fs

Lines changed: 28 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,6 @@ type internal AsyncEnumStatus =
1111
| WithCurrent
1212
| AfterAll
1313

14-
[<Struct>]
15-
type internal WhileKind =
16-
/// The item under test is included (or skipped) even when the predicate returns false
17-
| Inclusive
18-
/// The item under test is always excluded (or not skipped)
19-
| Exclusive
20-
2114
[<Struct>]
2215
type internal TakeOrSkipKind =
2316
/// use the Seq.take semantics, raises exception if not enough elements
@@ -813,8 +806,10 @@ module internal TaskSeqInternal =
813806

814807
| PredicateAsync asyncPredicate ->
815808
let mutable predicateHolds = true
816-
while hasMore && predicateHolds do
809+
810+
while hasMore && predicateHolds do // TODO: check perf if `while!` is going to be better or equal
817811
let! predicateIsTrue = asyncPredicate e.Current
812+
818813
if predicateIsTrue then
819814
yield e.Current
820815
let! cont = e.MoveNextAsync()
@@ -828,51 +823,42 @@ module internal TaskSeqInternal =
828823
yield e.Current
829824
}
830825

831-
let skipWhile whileKind predicate (source: TaskSeq<_>) =
826+
let skipWhile isInclusive predicate (source: TaskSeq<_>) =
832827
checkNonNull (nameof source) source
833828

834829
taskSeq {
835830
use e = source.GetAsyncEnumerator CancellationToken.None
831+
let! notEmpty = e.MoveNextAsync()
832+
let mutable hasMore = notEmpty
836833

837-
match! e.MoveNextAsync() with
838-
| false -> () // Nothing further to do, no matter what the rules are
839-
| true ->
840-
841-
let exclusive =
842-
match whileKind with
843-
| Exclusive -> true
844-
| Inclusive -> false
834+
match predicate with
835+
| Predicate synchronousPredicate ->
836+
while hasMore && synchronousPredicate e.Current do
837+
// keep skipping
838+
let! cont = e.MoveNextAsync()
839+
hasMore <- cont
845840

846-
let mutable cont = true
841+
| PredicateAsync asyncPredicate ->
842+
let mutable predicateHolds = true
847843

848-
match predicate with
849-
| Predicate predicate -> // skipWhile(Inclusive)?
850-
while cont do
851-
if predicate e.Current then // spam -> skip
852-
let! hasAnother = e.MoveNextAsync()
853-
cont <- hasAnother
854-
else // Starting the ham
855-
if exclusive then
856-
yield e.Current // return the item as it does not meet the condition for skipping
844+
while hasMore && predicateHolds do // TODO: check perf if `while!` is going to be better or equal
845+
let! predicateIsTrue = asyncPredicate e.Current
857846

858-
while! e.MoveNextAsync() do // propagate the rest
859-
yield e.Current
847+
if predicateIsTrue then
848+
// keep skipping
849+
let! cont = e.MoveNextAsync()
850+
hasMore <- cont
860851

861-
cont <- false
862-
| PredicateAsync predicate -> // skipWhile(Inclusive)?Async
863-
while cont do
864-
match! predicate e.Current with
865-
| true ->
866-
let! hasAnother = e.MoveNextAsync()
867-
cont <- hasAnother
868-
| false -> // We're starting the ham
869-
if exclusive then
870-
yield e.Current // return the item as it does not meet the condition for skipping
852+
predicateHolds <- predicateIsTrue
871853

872-
while! e.MoveNextAsync() do // propagate the rest
873-
yield e.Current
854+
// "inclusive" means: always skip the item that we pulled, regardless of the result of applying the predicate
855+
// and only stop thereafter. The non-inclusive versions, in contrast, do not skip the item under which the predicate is false.
856+
if hasMore && not isInclusive then
857+
yield e.Current // don't skip, unless inclusive
874858

875-
cont <- false
859+
// propagate the rest
860+
while! e.MoveNextAsync() do
861+
yield e.Current
876862
}
877863

878864
// Consider turning using an F# version of this instead?

0 commit comments

Comments
 (0)