123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118openCoreopenImportmoduleFd=Raw_fdtypet=Fd.tOption_array.tletcapacityt=Option_array.lengthtletcreate~num_file_descrs=ifnum_file_descrs<0thenraise_s[%message"[Fd_by_descr.create] got negative [num_file_descrs]"(num_file_descrs:int)];Option_array.create~len:num_file_descrs;;letbounds_checktfile_descr=leti=file_descr|>File_descr.to_intin0<=i&&i<capacityt;;letbounds_check_errortfile_descr=[%message"The file descriptor is not in the range that Async allows, which probably means \
that the program has created too many file descriptors without closing them. You \
can cause Async to allow more file descriptors via the [ASYNC_CONFIG] environment \
variable, like this: ASYNC_CONFIG='((max_num_open_file_descrs <NUMBER>))' foo.exe \
arg1 arg2 ..."(file_descr:File_descr.t)~min_file_descr:0~max_file_descr:(capacityt-1:int)];;letbounds_check_exntfile_descr=ifnot(bounds_checktfile_descr)thenraise_s(bounds_check_errortfile_descr);;letmemtfile_descr=bounds_checktfile_descr&&Option_array.is_somet(file_descr|>File_descr.to_int);;letfindtfile_descr=ifnot(bounds_checktfile_descr)thenNoneelseOption_array.gett(file_descr|>File_descr.to_int);;letfind_exntfile_descr=bounds_check_exntfile_descr;ifOption_array.is_nonet(file_descr|>File_descr.to_int)thenraise_s[%message"[Fd_by_descr.find_exn] got unknown file_descr"(file_descr:File_descr.t)];Option_array.get_some_exnt(file_descr|>File_descr.to_int);;letremovet(fd:Fd.t)=bounds_check_exntfd.file_descr;Option_array.set_nonet(fd.file_descr|>File_descr.to_int);;letaddt(fd:Fd.t)=letfile_descr=fd.file_descrinifnot(bounds_checktfile_descr)thenerror_s(bounds_check_errortfile_descr)elseifOption_array.is_somet(file_descr|>File_descr.to_int)thenerror_s[%message"Attempt to register a file descriptor with Async that Async believes it is \
already managing."]else(Option_array.set_somet(file_descr|>File_descr.to_int)fd;Ok());;letfoldt~init~f=letr=refinitinfori=0tocapacityt-1doifOption_array.is_sometithenr:=f!r(Option_array.get_some_exnti)done;!r;;letfoldit~init~f=letr=refinitinfori=0tocapacityt-1doifOption_array.is_sometithenr:=fi!r(Option_array.get_some_exnti)done;!r;;letitert~f=fori=0tocapacityt-1doifOption_array.is_sometithenf(Option_array.get_some_exnti)done;;(* The default sexp representation of this is huge and pollutes debug output *)letsexp_of_tt=letfd_alist=foldi~init:[]t~f:(funiaccfd->(i,fd)::acc)in[%sexp_of:(int*Fd.t)list](List.revfd_alist);;letinvariantt=tryfori=0tocapacityt-1domatchOption_array.gettiwith|None->()|Somefd->Fd.invariantfd;assert(File_descr.equal(i|>File_descr.of_int)(Fd.file_descrfd))donewith|exn->raise_s[%message"Fd_by_descr.invariant failure"(exn:exn)~fd:(t:t)];;