@@ -4,32 +4,56 @@ open System.Collections.Generic
44open FSharp.Data .Adaptive
55open FSharp.Data .Traceable
66
7- module Unique =
8- let mutable private currentId = 0 L
7+ [<Struct; CustomEquality; CustomComparison>]
8+ type Unique private ( value : int64 ) =
9+ static let mutable currentId = 0 L
10+ member private x.Value = value
911
10- let newId () =
11- System.Threading.Interlocked.Increment(& currentId)
12+ override x.GetHashCode () = hash value
13+ override x.Equals o =
14+ match o with
15+ | :? Unique as o -> value = o.Value
16+ | _ -> false
17+
18+ override x.ToString () = sprintf " U%04X " value
19+
20+ member x.CompareTo ( o : Unique ) =
21+ compare value o.Value
22+
23+ interface System.IComparable with
24+ member x.CompareTo o = x.CompareTo ( o :?> Unique)
25+
26+ member x.Equals ( o : Unique ) =
27+ value = o.Value
28+
29+ static member Invalid = Unique( 0 L)
30+
31+ member x.IsValid = value <> 0 L
32+ member x.IsInvalid = value = 0 L
33+
34+ static member New () =
35+ Unique( System.Threading.Interlocked.Increment(& currentId))
1236
1337type IAdaptiveBag < 'T > =
1438 /// Is the list constant?
1539 abstract member IsConstant : bool
1640
1741 /// The current content of the list as aval.
18- abstract member Content : aval < HashMap < int64 , 'T >>
42+ abstract member Content : aval < HashMap < Unique , 'T >>
1943
2044 /// Gets a new reader to the list.
2145 abstract member GetReader : unit -> IAdaptiveBagReader < 'T >
2246
2347 /// Gets the underlying History instance for the alist (if any)
24- abstract member History : option < History < HashMap < int64 , 'T >, HashMapDelta < int64 , 'T >>>
48+ abstract member History : option < History < HashMap < Unique , 'T >, HashMapDelta < Unique , 'T >>>
2549
26- and IAdaptiveBagReader < 'T > = IOpReader< HashMap< int64 , 'T>, HashMapDelta< int64 , 'T>>
50+ and IAdaptiveBagReader < 'T > = IOpReader< HashMap< Unique , 'T>, HashMapDelta< Unique , 'T>>
2751
2852and abag < 'T > = IAdaptiveBag< 'T>
2953
3054module ABag =
3155
32- type AdaptiveBag < 'T >( getReader : unit -> IOpReader < HashMapDelta < int64 , 'T >>) =
56+ type AdaptiveBag < 'T >( getReader : unit -> IOpReader < HashMapDelta < Unique , 'T >>) =
3357
3458 let history = new History<_,_>( getReader, HashMap.trace, ignore)
3559
@@ -46,7 +70,7 @@ module ABag =
4670 member x.Content =
4771 history :> aval<_>
4872
49- type ConstantBag < 'T >( content : Lazy < HashMap < int64 , 'T >>) =
73+ type ConstantBag < 'T >( content : Lazy < HashMap < Unique , 'T >>) =
5074
5175 let initialDelta =
5276 lazy (
@@ -68,19 +92,19 @@ module ABag =
6892 ConstantBag< 'T>(
6993 lazy (
7094 content
71- |> Seq.map ( fun e -> Unique.newId (), e)
95+ |> Seq.map ( fun e -> Unique.New (), e)
7296 |> HashMap.ofSeq
7397 )
7498 )
7599
76100 type private IdCache < 'a >() =
77- let table = DefaultDictionary.create< 'a, int64 >()
101+ let table = DefaultDictionary.create< 'a, Unique >()
78102
79103 member x.Invoke ( value : 'a ) =
80104 match table.TryGetValue value with
81105 | ( true , id) -> id
82106 | _ ->
83- let id = Unique.newId ()
107+ let id = Unique.New ()
84108 table.[ value] <- id
85109 id
86110
@@ -97,15 +121,24 @@ module ABag =
97121 table.Remove value |> ignore
98122 id
99123
100- let ofReader ( create : unit -> #IOpReader<HashMapDelta<int64 , 'T>> ) =
101- AdaptiveBag( fun () -> create() :> IOpReader<_>) :> abag<_>
102-
103124 let private constantSeq ( seq : unit -> seq < 'T >) =
104125 ConstantBag( Seq.delay seq) :> abag<_>
105126
106- let private constantMap ( seq : unit -> HashMap < int64 , 'T >) =
127+ let private constantMap ( seq : unit -> HashMap < Unique , 'T >) =
107128 ConstantBag( lazy ( seq())) :> abag<_>
108129
130+ let ofReader ( create : unit -> #IOpReader<HashMapDelta<Unique , 'T>> ) =
131+ AdaptiveBag( fun () -> create() :> IOpReader<_>) :> abag<_>
132+
133+ let ofSeq ( seq : seq < 'T >) =
134+ constantSeq ( fun () -> seq)
135+
136+ let ofList ( list : list < 'T >) =
137+ constantSeq ( fun () -> list)
138+
139+ let ofArray ( arr : 'T []) =
140+ constantSeq ( fun () -> arr)
141+
109142 let ofASet ( set : aset < 'T >) =
110143 if set.IsConstant then
111144 constantSeq <| fun () -> set.Content |> AVal.force :> seq<_>
@@ -128,7 +161,7 @@ module ABag =
128161 ) :> IOpReader<_>
129162 | None ->
130163 let r = set.GetReader()
131- { new AbstractReader< HashMapDelta< int64 , 'T>>( HashMapDelta.empty) with
164+ { new AbstractReader< HashMapDelta< Unique , 'T>>( HashMapDelta.empty) with
132165 member x.Compute ( token : AdaptiveToken ) =
133166 let ops = r.GetChanges token
134167 let mutable delta = HashMap.empty
@@ -167,7 +200,7 @@ module ABag =
167200 ) :> IOpReader<_>
168201 | None ->
169202 let r = list.GetReader()
170- { new AbstractReader< HashMapDelta< int64 , 'T>>( HashMapDelta.empty) with
203+ { new AbstractReader< HashMapDelta< Unique , 'T>>( HashMapDelta.empty) with
171204 member x.Compute ( token : AdaptiveToken ) =
172205 let ops = r.GetChanges token
173206 let mutable delta = HashMap.empty
@@ -184,7 +217,6 @@ module ABag =
184217 HashMapDelta delta
185218 } :> IOpReader<_>
186219
187-
188220 let mapAMap ( mapping : 'K -> 'V -> 'T ) ( map : amap < 'K , 'V >) =
189221 if map.IsConstant then
190222 constantSeq <| fun () -> map.Content |> AVal.force |> Seq.map ( fun ( k , v ) -> mapping k v) :> seq<_>
@@ -211,7 +243,7 @@ module ABag =
211243 history.NewReader( HashMap.trace, mapDelta) :> IOpReader<_>
212244 | None ->
213245 let r = map.GetReader()
214- { new AbstractReader< HashMapDelta< int64 , 'T>>( HashMapDelta.empty) with
246+ { new AbstractReader< HashMapDelta< Unique , 'T>>( HashMapDelta.empty) with
215247 member x.Compute ( token : AdaptiveToken ) =
216248 r.GetChanges token
217249 |> mapDelta
@@ -230,7 +262,7 @@ module ABag =
230262 if bag.IsConstant then
231263 constantMap <| fun () -> bag.Content |> AVal.force |> HashMap.map ( fun _ v -> mapping v)
232264 else
233- let inline mapDelta ( ops : HashMapDelta < int64 , 'T >) =
265+ let inline mapDelta ( ops : HashMapDelta < Unique , 'T >) =
234266 ops
235267 |> HashMapDelta.toHashMap
236268 |> HashMap.map ( fun k op ->
@@ -246,7 +278,7 @@ module ABag =
246278 history.NewReader( HashMap.trace, mapDelta) :> IOpReader<_>
247279 | None ->
248280 let r = bag.GetReader()
249- { new AbstractReader< HashMapDelta< int64 , 'U>>( HashMapDelta.empty) with
281+ { new AbstractReader< HashMapDelta< Unique , 'U>>( HashMapDelta.empty) with
250282 member x.Compute ( token : AdaptiveToken ) =
251283 r.GetChanges token
252284 |> mapDelta
@@ -259,7 +291,7 @@ module ABag =
259291 ofReader <| fun () ->
260292 let mutable existing = HashSet.empty
261293
262- let inline mapDelta ( ops : HashMapDelta < int64 , 'T >) =
294+ let inline mapDelta ( ops : HashMapDelta < Unique , 'T >) =
263295 ops
264296 |> HashMapDelta.toHashMap
265297 |> HashMap.choose ( fun k op ->
@@ -291,12 +323,57 @@ module ABag =
291323 history.NewReader( HashMap.trace, mapDelta) :> IOpReader<_>
292324 | None ->
293325 let r = bag.GetReader()
294- { new AbstractReader< HashMapDelta< int64 , 'U>>( HashMapDelta.empty) with
326+ { new AbstractReader< HashMapDelta< Unique , 'U>>( HashMapDelta.empty) with
295327 member x.Compute ( token : AdaptiveToken ) =
296328 r.GetChanges token
297329 |> mapDelta
298330 } :> IOpReader<_>
299-
331+
332+ let filter ( predicate : 'T -> bool ) ( bag : abag < 'T >) =
333+ if bag.IsConstant then
334+ constantMap <| fun () -> bag.Content |> AVal.force |> HashMap.filter ( fun _ v -> predicate v)
335+ else
336+ ofReader <| fun () ->
337+ let mutable existing = HashSet.empty
338+
339+ let inline mapDelta ( ops : HashMapDelta < Unique , 'T >) =
340+ ops
341+ |> HashMapDelta.toHashMap
342+ |> HashMap.choose ( fun k op ->
343+ match op with
344+ | Set v ->
345+ match predicate v with
346+ | true ->
347+ existing <- HashSet.add k existing
348+ Some ( Set v)
349+ | false ->
350+ match HashSet.tryRemove k existing with
351+ | Some n ->
352+ existing <- n
353+ Some Remove
354+ | None ->
355+ None
356+ | Remove ->
357+ match HashSet.tryRemove k existing with
358+ | Some n ->
359+ existing <- n
360+ Some Remove
361+ | None ->
362+ None
363+ )
364+ |> HashMapDelta.ofHashMap
365+
366+ match bag.History with
367+ | Some history ->
368+ history.NewReader( HashMap.trace, mapDelta) :> IOpReader<_>
369+ | None ->
370+ let r = bag.GetReader()
371+ { new AbstractReader< HashMapDelta< Unique, 'T>>( HashMapDelta.empty) with
372+ member x.Compute ( token : AdaptiveToken ) =
373+ r.GetChanges token
374+ |> mapDelta
375+ } :> IOpReader<_>
376+
300377 let unionMany ' ( bags : #seq<abag<'a>> ) =
301378 let bags =
302379 match bags :> seq<_> with
@@ -312,8 +389,8 @@ module ABag =
312389 else
313390 ofReader <| fun () ->
314391 let readers = bags |> Array.map ( fun b -> b.GetReader())
315- let caches = Array.init bags.Length ( fun _ -> IdCache< int64 >())
316- { new AbstractReader< HashMapDelta< int64 , 'a>>( HashMapDelta.empty) with
392+ let caches = Array.init bags.Length ( fun _ -> IdCache< Unique >())
393+ { new AbstractReader< HashMapDelta< Unique , 'a>>( HashMapDelta.empty) with
317394 member x.Compute ( token : AdaptiveToken ) =
318395 let mutable res = HashMap.empty
319396
@@ -346,13 +423,13 @@ module ABag =
346423 else
347424 ofReader <| fun () ->
348425 let reader = bag.GetReader()
349- let mutable readers = HashMap.empty< int64 , abag< 'b> * IOpReader< HashMap< int64 , 'b>, HashMapDelta< int64 , 'b>>>
426+ let mutable readers = HashMap.empty< Unique , abag< 'b> * IOpReader< HashMap< Unique , 'b>, HashMapDelta< Unique , 'b>>>
350427 let dirty = ref <| System.Collections.Generic.HashSet()
351428
352- { new AbstractReader< HashMapDelta< int64 , 'b>>( HashMapDelta.empty) with
429+ { new AbstractReader< HashMapDelta< Unique , 'b>>( HashMapDelta.empty) with
353430 member x.InputChangedObject ( _ , o ) =
354431 match o with
355- | : ? IOpReader < HashMap < int64 , 'b >, HashMapDelta < int64 , 'b >> as r when not ( System .Object .ReferenceEquals ( r , reader )) ->
432+ | : ? IOpReader < HashMap < Unique , 'b >, HashMapDelta < Unique , 'b >> as r when not ( System .Object .ReferenceEquals ( r , reader )) ->
356433 lock dirty ( fun () -> dirty.Value.Add r |> ignore)
357434 | _ ->
358435 ()
@@ -372,7 +449,7 @@ module ABag =
372449
373450 let inline newReader () =
374451 let newReader = newbag.GetReader()
375- let newCache = IdCache< int64 >()
452+ let newCache = IdCache< Unique >()
376453 newReader.Tag <- newCache
377454 dirty.Add newReader |> ignore
378455 readers <- HashMap.add lid ( newbag, newReader) readers
@@ -387,7 +464,7 @@ module ABag =
387464 // 1. remove the old reader
388465 // 2. add a new reader
389466 readers <- rest
390- let oldCache = oldReader.Tag :?> IdCache < int64 >
467+ let oldCache = oldReader.Tag :?> IdCache < Unique >
391468 dirty.Remove oldReader |> ignore
392469 oldReader.Outputs.Remove x |> ignore
393470 for oid, _ in oldReader.State do
@@ -404,7 +481,7 @@ module ABag =
404481 | Remove ->
405482 match HashMap.tryRemove lid readers with
406483 | Some((_, oldReader), rest) ->
407- let oldCache = oldReader.Tag :?> IdCache < int64 >
484+ let oldCache = oldReader.Tag :?> IdCache < Unique >
408485 readers <- rest
409486 dirty.Remove oldReader |> ignore
410487 oldReader.Outputs.Remove x |> ignore
@@ -416,7 +493,7 @@ module ABag =
416493 ()
417494
418495 for d in dirty do
419- let cache = d.Tag :?> IdCache < int64 >
496+ let cache = d.Tag :?> IdCache < Unique >
420497 let ops = d.GetChanges token
421498 for oid, op in ops do
422499 match op with
@@ -432,6 +509,9 @@ module ABag =
432509 HashMapDelta.ofHashMap delta
433510 }
434511
512+ let unionMany ( bags : abag < abag < 'T >>) =
513+ bags |> collect id
514+
435515 let toASet ( bag : abag < 'a >) =
436516 if bag.IsConstant then
437517 ASet.delay ( fun () -> bag.Content |> AVal.force |> HashMap.toValueSeq |> HashSet.ofSeq)
@@ -484,8 +564,8 @@ module ABag =
484564 )
485565 AList.ofReader <| fun () ->
486566 let r = bag.GetReader()
487- let indices = CustomIndexMapping< struct ( int64 * 'b)>( cmpt)
488- let mutable cache = HashMap.empty< int64 , 'b>
567+ let indices = CustomIndexMapping< struct ( Unique * 'b)>( cmpt)
568+ let mutable cache = HashMap.empty< Unique , 'b>
489569 { new AbstractReader< IndexListDelta< 'a>>( IndexListDelta.empty) with
490570 member x.Compute ( token : AdaptiveToken ) =
491571 let ops = r.GetChanges token
@@ -532,7 +612,7 @@ module ABag =
532612
533613 AList.ofReader <| fun () ->
534614 let r = bag.GetReader()
535- let indices = CustomIndexMapping< struct ( int64 * 'a)>( cmpt)
615+ let indices = CustomIndexMapping< struct ( Unique * 'a)>( cmpt)
536616 { new AbstractReader< IndexListDelta< 'a>>( IndexListDelta.empty) with
537617 member x.Compute ( token : AdaptiveToken ) =
538618 let old = r.State
0 commit comments