@@ -755,7 +755,85 @@ module AdaptiveHashMapImplementation =
755755 changes <- HashMap.add i ( Set v) changes
756756
757757 HashMapDelta.ofHashMap changes
758-
758+
759+ /// Reader for deltaA operations.
760+ [<Sealed>]
761+ type DeltaAReader < 'k , 'a , 'b >( input : amap < 'k , 'a >, mapping : HashMap < 'k , 'a > -> HashMap < 'k , aval < 'b >>) =
762+ inherit AbstractReader< HashMapDelta< 'k, 'b>>( HashMapDelta.empty)
763+
764+ let reader = input.GetReader()
765+ do reader.Tag <- " input"
766+ let cacheLock = obj()
767+ let mutable cache : HashMap < 'k , aval < 'b >> = HashMap.Empty
768+ let mutable targets = MultiSetMap.empty< aval< 'b>, 'k>
769+ let mutable dirty = HashMap.empty< 'k, aval< 'b>>
770+
771+ let consumeDirty () =
772+ lock cacheLock ( fun () ->
773+ let d = dirty
774+ dirty <- HashMap.empty
775+ d
776+ )
777+
778+ override x.InputChangedObject ( t , o ) =
779+ #if FABLE_ COMPILER
780+ if isNull o.Tag then
781+ let o = unbox< aval< 'b>> o
782+ for i in MultiSetMap.find o targets do
783+ dirty <- HashMap.add i o dirty
784+ #else
785+ match o with
786+ | :? aval< 'b> as o ->
787+ lock cacheLock ( fun () ->
788+ for i in MultiSetMap.find o targets do
789+ dirty <- HashMap.add i o dirty
790+ )
791+ | _ ->
792+ ()
793+ #endif
794+
795+ override x.Compute t =
796+ let mutable dirty = consumeDirty()
797+ let old = reader.State
798+ let ops = reader.GetChanges t |> HashMapDelta.toHashMap
799+
800+ let setOps , removeOps =
801+ (( HashMap.empty, HashMap.empty), ops)
802+ ||> HashMap.fold( fun ( sets , rems ) i op ->
803+ dirty <- HashMap.remove i dirty
804+ cache <-
805+ match HashMap.tryRemove i cache with
806+ | Some ( o, remaingCache) ->
807+ let rem , rest = MultiSetMap.remove o i targets
808+ targets <- rest
809+ if rem then o.Outputs.Remove x |> ignore
810+ remaingCache
811+ | None -> cache
812+ match op with
813+ | Set v ->
814+ HashMap.add i v sets, rems
815+ | Remove ->
816+ sets, HashMap.add i Remove rems
817+ )
818+
819+ let mutable changes =
820+ setOps
821+ |> mapping
822+ |> HashMap.map( fun i k ->
823+ cache <- HashMap.add i k cache
824+ let v = k.GetValue t
825+ targets <- MultiSetMap.add k i targets
826+ Set v
827+ )
828+
829+
830+ for i, d in dirty do
831+ let v = d.GetValue t
832+ changes <- HashMap.add i ( Set v) changes
833+
834+ HashMap.union removeOps changes
835+ |> HashMapDelta
836+
759837 /// Reader for chooseA operations.
760838 [<Sealed>]
761839 type ChooseAReader < 'k , 'a , 'b >( input : amap < 'k , 'a >, mapping : 'k -> 'a -> aval < Option < 'b >>) =
@@ -1333,6 +1411,19 @@ module AMap =
13331411 else
13341412 create ( fun () -> MapAReader( map, mapping))
13351413
1414+ /// Adaptively applies the given mapping to all changes.
1415+ let deltaA ( mapping : HashMap < 'K , 'T1 > -> HashMap < 'K , aval < 'T2 >>) ( map : amap < 'K , 'T1 >) =
1416+ if map.IsConstant then
1417+ let map = force map |> mapping
1418+ if map |> HashMap.forall ( fun _ v -> v.IsConstant) then
1419+ constant ( fun () -> map |> HashMap.map ( fun _ v -> AVal.force v))
1420+ else
1421+ // TODO better impl possible
1422+ create ( fun () -> MapAReader( ofHashMap map, fun _ v -> v))
1423+ else
1424+ create ( fun () -> DeltaAReader( map, mapping))
1425+
1426+
13361427 /// Adaptively chooses all elements returned by mapping.
13371428 let chooseA ( mapping : 'K -> 'T1 -> aval < Option < 'T2 >>) ( map : amap < 'K , 'T1 >) =
13381429 if map.IsConstant then
0 commit comments