123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960(*---------------------------------------------------------------------------
Copyright (c) 2018 The b0 programmers. All rights reserved.
SPDX-License-Identifier: ISC
---------------------------------------------------------------------------*)openB0_stdmoduleM=Map.Make(Int)type'akey={det:t->B0_memo.t->'aFut.t;id:'aType.Id.t;mark:string;}andbinding=B:'akey*'aFut.t->bindingandt={memo:B0_memo.t;mutablemap:bindingM.t;dir:Fpath.t}let[@inline]key_uidk=Type.Id.uidk.idletkey?(mark="")det={det;id=Type.Id.make();mark;}letmakememo~dirbs=letaddmap(B(k,_)asb)=M.add(key_uidk)bmapinletmap=List.fold_leftaddM.emptybsin{memo;map;dir;}letmemos=s.memoletdirs=s.dirletget:typea.t->akey->aFut.t=funsk->letkid=key_uidkinmatchM.find_optkids.mapwith|None->(* We don't use the key determination future directly because
its determination may indirectly trigger new gets of the same
key because the memo will be stired and possibly a [get] of
this key will occur before we get to indicate in the map that
the key is being determined. Using our own future here makes
sure all further [get]s end up in the other branch. *)letfut,set=Fut.make()ins.map<-M.addkid(B(k,fut))s.map;letmemo=(* XXX maybe it would be interesting to have a stack of marks
for build understanding "key via m ; m; m;" *)B0_memo.with_marks.memok.markinFut.await(k.detsmemo)set;fut|Some(B(k',fut))->matchType.Id.provably_equalk.idk'.idwith|SomeType.Equal->fut|None->assertfalseletsetskv=ifM.mem(key_uidk)s.mapthenFmt.invalid_arg"Key %s already set in store"k.markelseletfut=Fut.returnvins.map<-M.add(key_uidk)(B(k,fut))s.map