diff --git a/release-notes.txt b/release-notes.txt index d07e4fc..cfe2d7d 100644 --- a/release-notes.txt +++ b/release-notes.txt @@ -3,6 +3,8 @@ Release notes: 1.0.0 - adds taskSeqDynamic computation expression and TaskSeqDynamic/TaskSeqDynamicInfo types for dynamic (FSI-compatible) resumable code, fixing issue where taskSeq would raise NotImplementedException in F# Interactive, #246 + - perf: toResizeArrayAsync (and therefore toArrayAsync, toListAsync, toResizeArrayAsync, toIListAsync) uses a direct loop instead of going through iter, avoiding a lambda and DU allocation per call + - perf: tryItem uses a simpler loop that skips the redundant inner index check on every iteration - perf: TaskSeq.chunkBy and chunkByAsync reuse the ResizeArray buffer between chunks, reducing allocations on sequences with many chunk boundaries - fixes: TaskSeq.insertAt, insertManyAt, removeAt, removeManyAt, updateAt now raise ArgumentNullException (not NullReferenceException) when given a null source; insertManyAt also validates the values argument - refactor: simplify lengthBy and lengthBeforeMax to use while! and remove the redundant mutable 'go' and initial MoveNextAsync diff --git a/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs b/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs index 261dbba..b6f77a3 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs +++ b/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs @@ -532,12 +532,16 @@ module internal TaskSeqInternal = yield result } - let toResizeArrayAsync source = + let toResizeArrayAsync (source: TaskSeq<'T>) = checkNonNull (nameof source) source task { - let res = ResizeArray() - do! source |> iter (SimpleAction(fun item -> res.Add item)) + let res = ResizeArray<'T>() + use e = source.GetAsyncEnumerator CancellationToken.None + + while! e.MoveNextAsync() do + res.Add e.Current + return res } @@ -915,14 +919,14 @@ module internal TaskSeqInternal = let! step = e.MoveNextAsync() go <- step - while go && idx <= index do - if idx = index then - foundItem <- Some e.Current - go <- false - else - let! step = e.MoveNextAsync() - go <- step - idx <- idx + 1 + // advance past the first `index` elements, then capture the current element + while go && idx < index do + let! step = e.MoveNextAsync() + go <- step + idx <- idx + 1 + + if go then + foundItem <- Some e.Current return foundItem }