@@ -298,7 +298,11 @@ module ABag =
298298 } :> IOpReader<_>
299299
300300 let unionMany ' ( bags : #seq<abag<'a>> ) =
301- let bags = bags |> Seq.toArray
301+ let bags =
302+ match bags :> seq<_> with
303+ | :? array< abag< 'a>> as a -> a
304+ | _ -> bags |> Seq.toArray
305+
302306 if bags |> Array.forall ( fun b -> b.IsConstant) then
303307 constantSeq <| fun () ->
304308 seq {
@@ -333,97 +337,100 @@ module ABag =
333337 }
334338
335339 let union ( a : abag < 'a >) ( b : abag < 'a >) =
336- unionMany' [ a; b]
340+ unionMany' [| a; b| ]
337341
338342 let collect ( mapping : 'a -> abag < 'b >) ( bag : abag < 'a >) =
339- ofReader <| fun () ->
340- let reader = bag.GetReader()
341- let mutable readers = HashMap.empty< int64, abag< 'b> * IOpReader< HashMap< int64, 'b>, HashMapDelta< int64, 'b>>>
342- let dirty = ref <| System.Collections.Generic.HashSet()
343-
344- { new AbstractReader< HashMapDelta< int64, 'b>>( HashMapDelta.empty) with
345- member x.InputChangedObject ( _ , o ) =
346- match o with
347- | : ? IOpReader < HashMap < int64 , 'b >, HashMapDelta < int64 , 'b >> as r when not ( System .Object .ReferenceEquals ( r , reader )) ->
348- lock dirty ( fun () -> dirty.Value.Add r |> ignore)
349- | _ ->
350- ()
351-
352- member x.Compute ( token : AdaptiveToken ) =
353- let dirty =
354- lock dirty ( fun () ->
355- let d = dirty.Value
356- dirty.Value <- System.Collections.Generic.HashSet()
357- d
358- )
359- let mutable delta = HashMap.empty
360- for lid, op in reader.GetChanges token do
361- match op with
362- | Set nv ->
363- let newbag = mapping nv
364-
365- let inline newReader () =
366- let newReader = newbag.GetReader()
367- let newCache = IdCache< int64>()
368- newReader.Tag <- newCache
369- dirty.Add newReader |> ignore
370- readers <- HashMap.add lid ( newbag, newReader) readers
371-
372- match HashMap.tryRemove lid readers with
373- | Some (( oldBag, oldReader), _) when oldBag = newbag ->
374- // replaced with the identical bag
375- dirty.Add oldReader |> ignore
376-
377- | Some((_, oldReader), rest) ->
378- // replaced with a new bag =>
379- // 1. remove the old reader
380- // 2. add a new reader
381- readers <- rest
382- let oldCache = oldReader.Tag :?> IdCache < int64 >
383- dirty.Remove oldReader |> ignore
384- oldReader.Outputs.Remove x |> ignore
385- for oid, _ in oldReader.State do
386- match oldCache.TryRevoke oid with
387- | Some id -> delta <- HashMap.add id Remove delta
388- | None -> ()
389-
390- newReader()
391-
392- | _ ->
393- // insert
394- newReader()
395-
396- | Remove ->
397- match HashMap.tryRemove lid readers with
398- | Some((_, oldReader), rest) ->
399- let oldCache = oldReader.Tag :?> IdCache < int64 >
400- readers <- rest
401- dirty.Remove oldReader |> ignore
402- oldReader.Outputs.Remove x |> ignore
403- for oid, _ in oldReader.State do
404- match oldCache.TryRevoke oid with
405- | Some id -> delta <- HashMap.add id Remove delta
406- | None -> ()
407- | _ ->
408- ()
343+ if bag.IsConstant then
344+ let bags = bag.Content |> AVal.force |> HashMap.toValueArray |> Array.map mapping
345+ unionMany' bags
346+ else
347+ ofReader <| fun () ->
348+ let reader = bag.GetReader()
349+ let mutable readers = HashMap.empty< int64, abag< 'b> * IOpReader< HashMap< int64, 'b>, HashMapDelta< int64, 'b>>>
350+ let dirty = ref <| System.Collections.Generic.HashSet()
351+
352+ { new AbstractReader< HashMapDelta< int64, 'b>>( HashMapDelta.empty) with
353+ member x.InputChangedObject ( _ , o ) =
354+ match o with
355+ | : ? IOpReader < HashMap < int64 , 'b >, HashMapDelta < int64 , 'b >> as r when not ( System .Object .ReferenceEquals ( r , reader )) ->
356+ lock dirty ( fun () -> dirty.Value.Add r |> ignore)
357+ | _ ->
358+ ()
409359
410- for d in dirty do
411- let cache = d.Tag :?> IdCache < int64 >
412- let ops = d.GetChanges token
413- for oid, op in ops do
360+ member x.Compute ( token : AdaptiveToken ) =
361+ let dirty =
362+ lock dirty ( fun () ->
363+ let d = dirty.Value
364+ dirty.Value <- System.Collections.Generic.HashSet()
365+ d
366+ )
367+ let mutable delta = HashMap.empty
368+ for lid, op in reader.GetChanges token do
414369 match op with
415- | Set value ->
416- let id = cache.Invoke oid
417- delta <- HashMap.add id ( Set value) delta
370+ | Set nv ->
371+ let newbag = mapping nv
372+
373+ let inline newReader () =
374+ let newReader = newbag.GetReader()
375+ let newCache = IdCache< int64>()
376+ newReader.Tag <- newCache
377+ dirty.Add newReader |> ignore
378+ readers <- HashMap.add lid ( newbag, newReader) readers
379+
380+ match HashMap.tryRemove lid readers with
381+ | Some (( oldBag, oldReader), _) when oldBag = newbag ->
382+ // replaced with the identical bag
383+ dirty.Add oldReader |> ignore
384+
385+ | Some((_, oldReader), rest) ->
386+ // replaced with a new bag =>
387+ // 1. remove the old reader
388+ // 2. add a new reader
389+ readers <- rest
390+ let oldCache = oldReader.Tag :?> IdCache < int64 >
391+ dirty.Remove oldReader |> ignore
392+ oldReader.Outputs.Remove x |> ignore
393+ for oid, _ in oldReader.State do
394+ match oldCache.TryRevoke oid with
395+ | Some id -> delta <- HashMap.add id Remove delta
396+ | None -> ()
397+
398+ newReader()
399+
400+ | _ ->
401+ // insert
402+ newReader()
403+
418404 | Remove ->
419- let id = cache.Revoke oid
420- delta <- HashMap.add id Remove delta
405+ match HashMap.tryRemove lid readers with
406+ | Some((_, oldReader), rest) ->
407+ let oldCache = oldReader.Tag :?> IdCache < int64 >
408+ readers <- rest
409+ dirty.Remove oldReader |> ignore
410+ oldReader.Outputs.Remove x |> ignore
411+ for oid, _ in oldReader.State do
412+ match oldCache.TryRevoke oid with
413+ | Some id -> delta <- HashMap.add id Remove delta
414+ | None -> ()
415+ | _ ->
416+ ()
421417
422- dirty.Clear()
418+ for d in dirty do
419+ let cache = d.Tag :?> IdCache < int64 >
420+ let ops = d.GetChanges token
421+ for oid, op in ops do
422+ match op with
423+ | Set value ->
424+ let id = cache.Invoke oid
425+ delta <- HashMap.add id ( Set value) delta
426+ | Remove ->
427+ let id = cache.Revoke oid
428+ delta <- HashMap.add id Remove delta
423429
424- HashMapDelta.ofHashMap delta
425- }
430+ dirty.Clear()
426431
432+ HashMapDelta.ofHashMap delta
433+ }
427434
428435 let toASet ( bag : abag < 'a >) =
429436 if bag.IsConstant then
0 commit comments