Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file carbonated_map.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2021-2022 Trili Tech, <contact@trili.tech> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)moduletypeS=sigtype'attypekeytypecontextvalempty:'atvalsingleton:key->'a->'atvalsize:'at->intvalfind:context->key->'at->('aoption*context)tzresultvalupdate:context->key->(context->'aoption->('aoption*context)tzresult)->'at->('at*context)tzresultvalto_list:context->'at->((key*'a)list*context)tzresultvalof_list:context->merge_overlap:(context->'a->'a->('a*context)tzresult)->(key*'a)list->('at*context)tzresultvalmerge:context->merge_overlap:(context->'a->'a->('a*context)tzresult)->'at->'at->('at*context)tzresultvalmap_e:context->(context->key->'a->('b*context)tzresult)->'at->('bt*context)tzresultvalfold_e:context->(context->'state->key->'value->('state*context)tzresult)->'state->'valuet->('state*context)tzresultvalfold_es:context->(context->'state->key->'value->('state*context)tzresultLwt.t)->'state->'valuet->('state*context)tzresultLwt.tendmoduletypeGAS=sigtypecontextvalconsume:context->Saturation_repr.may_saturateSaturation_repr.t->contexttzresultendmoduletypeCOMPARABLE=sigincludeCompare.COMPARABLE(** [compare_cost k] returns the cost of comparing the given key [k] with
another value of the same type. *)valcompare_cost:t->Saturation_repr.may_saturateSaturation_repr.tendmoduleMake_builder(C:COMPARABLE)=structmoduleM=Map.Make(C)type'at={map:'aM.t;size:int}moduleMake(G:GAS):Swithtypekey=C.tandtypecontext=G.contextandtype'at:='at=structtypekey=C.ttypecontext=G.contextletempty={map=M.empty;size=0}letsingletonkeyvalue={map=M.singletonkeyvalue;size=1}letsize{size;_}=sizeletfind_cost~key~size=Carbonated_map_costs.find_cost~compare_key_cost:(C.compare_costkey)~sizeletupdate_cost~key~size=Carbonated_map_costs.update_cost~compare_key_cost:(C.compare_costkey)~sizeletfindctxtkey{map;size}=G.consumectxt(find_cost~key~size)>|?functxt->(M.findkeymap,ctxt)letupdatectxtkeyf{map;size}=letfind_cost=find_cost~key~sizeinletupdate_cost=update_cost~key~sizein(* Consume gas for looking up the old value *)G.consumectxtfind_cost>>?functxt->letold_val_opt=M.findkeymapin(* The call to [f] must also account for gas *)fctxtold_val_opt>>?fun(new_val_opt,ctxt)->match(old_val_opt,new_val_opt)with|Some_,Somenew_val->(* Consume gas for adding to the map *)G.consumectxtupdate_cost>|?functxt->({map=M.addkeynew_valmap;size},ctxt)|Some_,None->(* Consume gas for removing from the map *)G.consumectxtupdate_cost>|?functxt->({map=M.removekeymap;size=size-1},ctxt)|None,Somenew_val->(* Consume gas for adding to the map *)G.consumectxtupdate_cost>|?functxt->({map=M.addkeynew_valmap;size=size+1},ctxt)|None,None->ok({map;size},ctxt)letto_listctxt{map;size}=G.consumectxt(Carbonated_map_costs.fold_cost~size)>|?functxt->(M.bindingsmap,ctxt)letaddctxt~merge_overlapkeyvalue{map;size}=(* Consume gas for looking up the element *)G.consumectxt(find_cost~key~size)>>?functxt->(* Consume gas for adding the element *)G.consumectxt(update_cost~key~size)>>?functxt->matchM.findkeymapwith|Someold_val->(* Invoking [merge_overlap] must also account for gas *)merge_overlapctxtold_valvalue>|?fun(new_value,ctxt)->({map=M.addkeynew_valuemap;size},ctxt)|None->Ok({map=M.addkeyvaluemap;size=size+1},ctxt)letadd_key_values_to_mapctxt~merge_overlapmapkey_values=letaccum(map,ctxt)(key,value)=addctxt~merge_overlapkeyvaluemapin(* Gas is paid at each step of the fold. *)List.fold_left_eaccum(map,ctxt)key_valuesletof_listctxt~merge_overlap=add_key_values_to_mapctxt~merge_overlapemptyletmergectxt~merge_overlapmap1{map;size}=(* To be on the safe side, pay an upfront gas cost for traversing the
map. Each step of the fold is accounted for separately.
*)G.consumectxt(Carbonated_map_costs.fold_cost~size)>>?functxt->M.fold_e(funkeyvalue(map,ctxt)->addctxt~merge_overlapkeyvaluemap)map(map1,ctxt)letfold_ectxtfempty{map;size}=G.consumectxt(Carbonated_map_costs.fold_cost~size)>>?functxt->M.fold_e(funkeyvalue(acc,ctxt)->(* Invoking [f] must also account for gas. *)fctxtacckeyvalue)map(empty,ctxt)letfold_esctxtfempty{map;size}=G.consumectxt(Carbonated_map_costs.fold_cost~size)>>?=functxt->M.fold_es(funkeyvalue(acc,ctxt)->(* Invoking [f] must also account for gas. *)fctxtacckeyvalue)map(empty,ctxt)letmap_ectxtf{map;size}=(* We cannot use the standard map function because [f] also meters the gas
cost at each invocation. *)fold_ectxt(functxtmapkeyvalue->(* Invoking [f] must also account for gas. *)fctxtkeyvalue>>?fun(value,ctxt)->(* Consume gas for adding the element. *)G.consumectxt(update_cost~key~size)>|?functxt->(M.addkeyvaluemap,ctxt))M.empty{map;size}>|?fun(map,ctxt)->({map;size},ctxt)endendmoduleMake(G:GAS)(C:COMPARABLE):Swithtypekey=C.tandtypecontext=G.context=structmoduleM=Make_builder(C)type'at='aM.tincludeM.Make(G)end