Skip to content

Commit 7f16b4a

Browse files
committed
micro optimization for ABag.unionMany
1 parent 78bcca2 commit 7f16b4a

1 file changed

Lines changed: 91 additions & 84 deletions

File tree

src/Demo/Scratch/ABag.fs

Lines changed: 91 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)