123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166(* dynamic variables with immediate or delayed execution *)(* one could use this for the whole rendering process of everything (like in
ELM): Layout.t would be replaced by Layout.t Dynvar.t. But I'm not sure it's
a good idea. If you have a complicated layout and only one small part
changes, it seems to me you would have to recompute everything et each
frame. Or, we need a mechanism to impose the scope of the modifications. *)(* TODO: make thus a functor to specialize equality *)(* this module is not used yet *)openTsdlopenB_utilsmoduleVar=B_varmoduleTrigger=B_trigger(* just to keep track of created threads... not used? *)letthreads_created=Var.create[]letadd_threadt=Var.updatethreads_created(List.const)letremove_threadt=Var.updatethreads_created(List.filter(funt'->t'<>t))type'at={id:int;mutabledata:'a;mutablechanged:bool;(* not used ? *)update:Sdl.event->'a->'a;events:Sdl.event_typelist(* the list of events that change this variable *)}(* table (event_type, id) = the id of the variables that are modified by the
event of this type (multivalued) *)letvar_event_table:(Sdl.event_type,int)Hashtbl.t=Hashtbl.create100(* "reciprocal table" : table (id, ev): the vars that have changed
(multivalued), and the corresponding events *)letvar_to_update_table:(int,Sdl.event)Hashtbl.t=Hashtbl.create100letnew_id=fresh_int()(** create a new dynvar which reacts to the event types listed in ~event, and
update itself by applying the ~update function to each event *)letcreate~update~eventsx=letid=new_id()inletv={id;data=x;changed=false;update;events}inList.iter(funtyp->printddebug_warning"Add (%u, %u)"typid;Hashtbl.addvar_event_tabletypid)events;(* can have several vars per event type *)vletfail__=failwith"This var cannot update itself"(** create a "manual" dynvar which does react to any event, but which can be
modified manually with modify *)letof_valuex=create~update:fail~events:[]xletsend_event_var_changedv=Trigger.push_var_changedv.id(* Do we really need to send several such events? maybe only one is enough, and
the user code is not used. Another option would be to store in var.events the
var_id ... *)(** manually modify a dynvar *)letmodifyvx=ifx<>v.datathenbegin(* TODO specialize equality *)v.data<-x;v.changed<-true;send_event_var_changedvendletupdate_varvev=printddebug_warning"Update dynvar #%u"v.id;modifyv(v.updateevv.data);Hashtbl.removevar_to_update_tablev.id(** get (or compute) the value of the dynvar *)letvaluev=let()=tryletevs=Hashtbl.find_allvar_to_update_tablev.idinList.iter(update_varv)evs;with|Not_found->()inv.data(** create a new dynvar by applying a the function f to the value of v.
If v is modified in the future, then the new dynvar will be updated
accordingly *)letapplyfv=letx=f(valuev)inletupdate__=f(valuev)inletevents=Trigger.var_changed::v.eventsin(* or already there? *)create~update~eventsx(* this should be called with every new event in the mainloop. *)letprocess_eventev=letev_type=Sdl.Event.(getevtyp)inletids=Hashtbl.find_allvar_event_tableev_typeinList.iter(funid->printddebug_warning"Add to update: (id:%u, ev:%u)"idev_type;Hashtbl.addvar_to_update_tableidev)ids(** create a var with the result of a computation done in another thread *)(* we need a default value to start with *)letasync_computefdefault=letv=create~events:[]~update:faildefaultinletg=fun()->letresult=f()inmodifyvresult;remove_thread(Thread.self())inadd_thread(Thread.createg());v(***************************************************)lettest()=letu=of_value0inletfx=x+1inletv=applyfuinletgx=x*2inletw=applygvinprintddebug_warning"w=%u"(valuew);modifyu1;letev=Trigger.(wait_event!my_event)inprocess_eventev;printddebug_warning"w=%u"(valuew);letev=Trigger.(wait_event!my_event)inprocess_eventev;printddebug_warning"w=%u"(valuew);letmy_long_computation()=printddebug_thread"Starting computation...";Thread.delay3.;printddebug_thread"Computation finished !";123inletau=async_computemy_long_computation0inletv=applyfauinprintddebug_warning"au=%u, v=%u"(valueau)(valuev);letrecloopt0=ifUnix.gettimeofday()-.t0>4.then()elsebeginletev=Trigger.(wait_event!my_event)inprocess_eventev;printddebug_warning"au=%u, v=%u"(valueau)(valuev);Thread.delay0.1;loopt0endinloop(Unix.gettimeofday())(*
Local Variables:
tuareg-interactive-program:"./bogue.top"
typerex-interactive-program:"./threadtop -I +threads"
compile-command:"make -k"
End:
*)