123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173(****************************************************************
* Generic utility functions
*
* Copyright Arm Limited (c) 2017-2019
* SPDX-Licence-Identifier: BSD-3-Clause
****************************************************************)(** Generic utility functions *)(****************************************************************
* Pretty-printer related
****************************************************************)letto_string(d:PPrintEngine.document):string=letbuf=Buffer.create100inPPrintEngine.ToBuffer.compactbufd;Buffer.contentsbuf(****************************************************************
* List related
****************************************************************)letnub(xs:'alist):'alist=letrecnub_auxseenxs=(matchxswith|[]->seen|(y::ys)->ifList.memyseenthennub_auxseenyselsenub_aux(y::seen)ys)innub_aux[]xsletzip_list(xs:'alist)(ys:'blist):('a*'b)list=List.map2(funxy->(x,y))xsysletzipWithIndex(f:'a->int->'b)(xs:'alist):'blist=letrecauxixs=(matchxswith|[]->[]|(y::ys)->fyi::aux(i+1)ys)inaux0xs(****************************************************************
* Option related
****************************************************************)letisNone(ox:'aoption):bool=(matchoxwith|None->true|Some_->false)letmap_option(f:'a->'b)(ox:'aoption):'boption=(matchoxwith|None->None|Somex->Some(fx))letget_option(ox:'aoption):'a=(matchoxwith|None->raiseNot_found|Somex->x)letfrom_option(ox:'aoption)(d:unit->'a):'a=(matchoxwith|None->d()|Somex->x)letbind_option(ox:'aoption)(f:'a->'boption):'boption=(matchoxwith|None->None|Somex->fx)letorelse_option(ox:'aoption)(f:unit->'aoption):'aoption=(matchoxwith|None->f()|Some_->ox)letrecconcat_option(oss:(('alist)option)list):('alist)option=(matchosswith|[]->Some[]|None::_->None|(Somexs)::xss->map_option(List.appendxs)(concat_optionxss))(* extract all non-None elements from a list *)letflatten_option(os:('aoption)list):'alist=letrecauxros=(matchoswith|[]->List.revr|Someo::os'->aux(o::r)os'|None::os'->auxros')inaux[]os(* extract all non-None elements from a list *)letflatmap_option(f:'a->'boption)(xs:'alist):'blist=letrecauxrxs=(matchxswith|[]->List.revr|x::xs'->(matchfxwith|Someb->aux(b::r)xs'|None->auxrxs'))inaux[]xs(* todo: give this a better name *)letflatten_map_option(f:'a->'boption)(xs:'alist):'blistoption=letrecauxrxs=(matchxswith|[]->Some(List.revr)|x::xs'->(matchfxwith|Someb->aux(b::r)xs'|None->None))inaux[]xs(* find first non-None result from function 'f' on list 'xs' *)letrecfirst_option(f:'a->'boption)(xs:'alist):'boption=(matchxswith|[]->None|x::xs'->(matchfxwith|Someb->Someb|None->first_optionfxs'))(****************************************************************
* String related
****************************************************************)(** Test whether 'x' starts with (is prefixed by) 'y' *)letstartswith(x:string)(y:string):bool=letlx=String.lengthxinletly=String.lengthyiniflx<lythenbeginfalseendelsebeginlethead=String.subx0lyinString.equalheadyend(** Test whether 'x' ends with (is suffixed by) 'y' *)letendswith(x:string)(y:string):bool=letlx=String.lengthxinletly=String.lengthyiniflx<lythenbeginfalseendelsebeginlettail=String.subx(lx-ly)lyinString.equaltailyend(** Drop first n characters from string *)letstringDrop(n:int)(s:string):string=letl=String.lengthsinifn>lthenbegin""endelsebeginString.subsn(l-n)end(****************************************************************
* End
****************************************************************)