123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169(*
* Copyright (C) Citrix Systems Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; version 2.1 only. with the special
* exception on linking described in file LICENSE.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*)moduleNode=structtype('a,'b)t={key:'a;value:'boption;children:('a,'b)tlist;}letemptykey={key=key;value=None;children=[]}letget_valuenode=matchnode.valuewith|None->raiseNot_found|Somevalue->valueletset_valuenodevalue={nodewithvalue=Somevalue}letset_childrennodechildren={nodewithchildren=children}endtype('a,'b)t=('a,'b)Node.tlistletmem_nodenodeskey=List.exists(funn->n.Node.key=key)nodesletfind_nodenodeskey=List.find(funn->n.Node.key=key)nodesletreplace_nodenodeskeynode=letrecaux=function|[]->[]|h::tlwhenh.Node.key=key->node::tl|h::tl->h::auxtlinauxnodesletremove_nodenodeskey=letrecaux=function|[]->raiseNot_found|h::tlwhenh.Node.key=key->tl|h::tl->h::auxtlinauxnodesletcreate()=[]letreciterftree=letauxnode=fnode.Node.keynode.Node.value;iterfnode.Node.childreninList.iterauxtreeletrecmapftree=letauxnode=letvalue=matchnode.Node.valuewith|None->None|Somevalue->fvaluein{nodewithNode.value=value;Node.children=mapfnode.Node.children}inList.filter(funn->n.Node.value<>None||n.Node.children<>[])(List.mapauxtree)letrecfoldftreeacc=letauxaccunode=foldfnode.Node.children(fnode.Node.keynode.Node.valueaccu)inList.fold_leftauxacctree(* return a sub-trie *)letrecsub_nodetree=function|[]->raiseNot_found|h::t->ifmem_nodetreehthenbeginletnode=find_nodetreehinift=[]thennodeelsesub_nodenode.Node.childrentendelseraiseNot_foundletsubtreepath=try(sub_nodetreepath).Node.childrenwithNot_found->[]letfindtreepath=Node.get_value(sub_nodetreepath)(* return false if the node doesn't exists or if it is not associated to any value *)letrecmemtree=function|[]->false|h::t->mem_nodetreeh&&(letnode=find_nodetreehinift=[]thennode.Node.value<>Noneelsememnode.Node.childrent)(* Iterate over the longest valid prefix *)letreciter_pathftree=function|[]->()|h::l->ifmem_nodetreehthenbeginletnode=find_nodetreehinfnode.Node.keynode.Node.value;iter_pathfnode.Node.childrenlendletrecset_nodenodepathvalue=ifpath=[]thenNode.set_valuenodevalueelsebeginletchildren=setnode.Node.childrenpathvalueinNode.set_childrennodechildrenendandsettreepathvalue=matchpathwith|[]->raiseNot_found|h::t->ifmem_nodetreehthenbeginletnode=find_nodetreehinreplace_nodetreeh(set_nodenodetvalue)endelsebeginletnode=Node.emptyhinset_nodenodetvalue::treeendletrecunsettree=function|[]->tree|h::t->ifmem_nodetreehthenbeginletnode=find_nodetreehinletchildren=unsetnode.Node.childrentinletnew_node=ift=[]thenNode.set_children(Node.emptyh)childrenelseNode.set_childrennodechildreninifchildren=[]&&new_node.Node.value=Nonethenremove_nodetreehelsereplace_nodetreehnew_nodeendelseraiseNot_found