@@ -591,49 +591,62 @@ module AsyncSeq =
591591 | HaveInnerEnumerator of IAsyncEnumerator < 'T > * IAsyncEnumerator < 'U >
592592 | Finished
593593
594+ // Optimized collect implementation using direct field access instead of ref cells
595+ type OptimizedCollectEnumerator < 'T , 'U >( f : 'T -> AsyncSeq < 'U >, inp : AsyncSeq < 'T >) =
596+ // Mutable fields instead of ref cells to reduce allocations
597+ let mutable inputEnumerator : IAsyncEnumerator < 'T > option = None
598+ let mutable innerEnumerator : IAsyncEnumerator < 'U > option = None
599+ let mutable disposed = false
600+
601+ // Tail-recursive optimization to avoid deep continuation chains
602+ let rec moveNextLoop () : Async < 'U option > = async {
603+ if disposed then return None
604+ else
605+ match innerEnumerator with
606+ | Some inner ->
607+ let! result = inner.MoveNext()
608+ match result with
609+ | Some value -> return Some value
610+ | None ->
611+ inner.Dispose()
612+ innerEnumerator <- None
613+ return ! moveNextLoop ()
614+ | None ->
615+ match inputEnumerator with
616+ | Some outer ->
617+ let! result = outer.MoveNext()
618+ match result with
619+ | Some value ->
620+ let newInner = ( f value). GetEnumerator()
621+ innerEnumerator <- Some newInner
622+ return ! moveNextLoop ()
623+ | None ->
624+ outer.Dispose()
625+ inputEnumerator <- None
626+ disposed <- true
627+ return None
628+ | None ->
629+ let newOuter = inp.GetEnumerator()
630+ inputEnumerator <- Some newOuter
631+ return ! moveNextLoop ()
632+ }
633+
634+ interface IAsyncEnumerator< 'U> with
635+ member _.MoveNext () = moveNextLoop ()
636+ member _.Dispose () =
637+ if not disposed then
638+ disposed <- true
639+ match innerEnumerator with
640+ | Some inner -> inner.Dispose(); innerEnumerator <- None
641+ | None -> ()
642+ match inputEnumerator with
643+ | Some outer -> outer.Dispose(); inputEnumerator <- None
644+ | None -> ()
645+
594646 let collect ( f : 'T -> AsyncSeq < 'U >) ( inp : AsyncSeq < 'T >) : AsyncSeq < 'U > =
595- { new IAsyncEnumerable< 'U> with
596- member x.GetEnumerator () =
597- let state = ref ( CollectState.NotStarted inp)
598- { new IAsyncEnumerator< 'U> with
599- member x.MoveNext () =
600- async { match ! state with
601- | CollectState.NotStarted inp ->
602- return !
603- ( let e1 = inp.GetEnumerator()
604- state := CollectState .HaveInputEnumerator e1
605- x.MoveNext())
606- | CollectState.HaveInputEnumerator e1 ->
607- let! res1 = e1.MoveNext()
608- return !
609- ( match res1 with
610- | Some v1 ->
611- let e2 = ( f v1). GetEnumerator()
612- state := CollectState .HaveInnerEnumerator ( e1 , e2 )
613- | None ->
614- x.Dispose()
615- x.MoveNext())
616- | CollectState.HaveInnerEnumerator ( e1, e2) ->
617- let! res2 = e2.MoveNext()
618- match res2 with
619- | None ->
620- state := CollectState .HaveInputEnumerator e1
621- dispose e2
622- return ! x.MoveNext()
623- | Some _ ->
624- return res2
625- | _ ->
626- return None }
627- member x.Dispose () =
628- match ! state with
629- | CollectState.HaveInputEnumerator e1 ->
630- state := CollectState.Finished
631- dispose e1
632- | CollectState.HaveInnerEnumerator ( e1, e2) ->
633- state := CollectState.Finished
634- dispose e2
635- dispose e1
636- | _ -> () } }
647+ { new IAsyncEnumerable< 'U> with
648+ member _.GetEnumerator () =
649+ new OptimizedCollectEnumerator< 'T, 'U>( f, inp) :> IAsyncEnumerator < 'U > }
637650
638651// let collect (f: 'T -> AsyncSeq<'U>) (inp: AsyncSeq<'T>) : AsyncSeq<'U> =
639652// AsyncGenerator.collect f inp
0 commit comments