123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114(**************************************************************************)(* This file is part of the Codex semantics library. *)(* *)(* Copyright (C) 2013-2025 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* 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. *)(* *)(* It 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. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file LICENSE). *)(* *)(**************************************************************************)(* Memory-efficient replacement for maps, useful when we have a lot of
small maps. *)moduleMake(Key:Map.OrderedType)=structmoduleM=Map.Make(Key)typekey=Key.t(* Small maps, with keys in increasing order.*)type'at=|Empty|Oneof{key1:Key.t;value1:'a}|Twoof{key1:Key.t;value1:'a;key2:Key.t;value2:'a}|Threeof{key1:Key.t;value1:'a;key2:Key.t;value2:'a;key3:Key.t;value3:'a;}|Largeof'aM.t;;letfindkeymap=matchmapwith|Empty->raiseNot_found|One{key1;value1}->ifKey.comparekeykey1=0thenvalue1elseraiseNot_found|Two{key1;value1;key2;value2}->beginmatchKey.comparekeykey1with|0->value1|xwhen(* x > 0 && *)Key.comparekeykey2=0->value2|_->raiseNot_foundend|Three{key1;value1;key2;value2;key3;value3}->beginmatchKey.comparekeykey2with|0->value2|xwhenx<0->ifKey.comparekeykey1=0thenvalue1elseraiseNot_found|_->ifKey.comparekeykey3=0thenvalue3elseraiseNot_foundend(* begin
* if Key.compare key key1 = 0 then value1
* else if Key.compare key key2 = 0 then value2
* else if Key.compare key key3 = 0 then value3
* else raise Not_found *)|Largem->M.findkeym;;letbindings=function|Empty->[]|One{key1;value1}->[(key1,value1)]|Two{key1;value1;key2;value2}->[(key1,value1);(key2,value2)]|Three{key1;value1;key2;value2;key3;value3}->[(key1,value1);(key2,value2);(key3,value3)]|Largem->M.bindingsmletfoldfminit=matchmwith|Empty->init|One{key1;value1}->fkey1value1init|Two{key1;value1;key2;value2}->fkey2value2@@fkey1value1init|Three{key1;value1;key2;value2;key3;value3}->fkey3value3@@fkey2value2@@fkey1value1init|Largem->M.foldfminitletaddkeyvaluemap=matchmapwith|Empty->One{key1=key;value1=value}|One{key1;value1}->beginmatchKey.comparekeykey1with|0->One{key1;value1=value}|xwhenx<0->Two{key1=key;value1=value;key2=key1;value2=value1}|_->Two{key1;value1;key2=key;value2=value}end|Two{key1;value1;key2;value2}->beginmatchKey.comparekeykey1with|0->Two{key1;value1=value;key2;value2}|xwhenx<0->Three{key1=key;value1=value;key2=key1;value2=value1;key3=key2;value3=value2}|_->beginmatchKey.comparekeykey2with|0->Two{key1;value1;key2;value2=value}|xwhenx<0->Three{key1;value1;key2=key;value2=value;key3=key2;value3=value2}|_->Three{key1;value1;key2;value2;key3=key;value3=value}endend|Three{key1;value1;key2;value2;key3;value3}->beginmatchKey.comparekeykey2with|0->Three{key1;value1;key2;value2=value;key3;value3}|xwhenx<0&&Key.comparekeykey1=0->Three{key1;value1=value;key2;value2;key3;value3}|xwhenx>0&&Key.comparekeykey3=0->Three{key1;value1;key2;value2;key3;value3=value}|_->Large(M.addkeyvalue@@M.addkey3value3@@M.addkey2value2@@M.singletonkey1value1)end|Largem->Large(M.addkeyvaluem);;letempty=Emptyend