123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103(******************************************************************************)(* *)(* Fix *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright Inria. All rights reserved. This file is distributed under the *)(* terms of the GNU Library General Public License version 2, with a *)(* special exception on linking, as described in the file LICENSE. *)(* *)(******************************************************************************)openSigsletforceo=matchowithSomex->x|None->assertfalsemoduleMake(M:IMPERATIVE_MAPS)=structtypet=M.key(* Create a generator of fresh integers. *)openGensymletg=generator()letcurrent()=currentg(* Memoizing the function [fun _ -> fresh g] yields the function [encode],
which maps keys to unique integers. We use [visibly_memoize] so as to
have access to the memoization table. This allows us to use operations
such as [M.find] and [M.iter] below. *)let(encode:t->int),(table:intM.t)=letmoduleMemo=Memoize.Make(M)inMemo.visibly_memoize(fun(_:t)->freshg)(* Testing whether a key has been encountered already. *)lethas_been_encoded(x:t):bool=(* We do not have [M.mem], so we re-implement it in terms of [M.find]. *)trylet_=M.findxtableintruewithNot_found->false(* Building a mapping of integer codes back to keys. *)letreverse_mapping():tarray=letn=current()inletreverse:toptionarray=Array.makenNoneinM.iter(funxi->reverse.(i)<-Somex)table;Array.mapforcereversemoduleDone()=structtypet=M.keyletn=current()letencodex=(* It would be an error to try and encode new keys now. Thus, if
[x] has not been encountered before, the client is at fault.
Fail with a nice informative message. *)ifhas_been_encodedxthenencodexelsePrintf.sprintf"Fix.Numbering: invalid argument passed to \"encode\".\n%s\n"__LOC__|>invalid_argletreverse=reverse_mapping()letdecodei=if0<=i&&i<nthenreverse.(i)elsePrintf.sprintf"Fix.Numbering: invalid argument passed to \"decode\".\n\
The index %d is not in the range [0, %d).\n%s\n"in__LOC__|>invalid_argendendmoduleForOrderedType(T:OrderedType)=Make(Glue.PersistentMapsToImperativeMaps(Map.Make(T)))moduleForHashedType(T:HashedType)=Make(Glue.HashTablesAsImperativeMaps(T))moduleForType(T:TYPE)=ForHashedType(Glue.TrivialHashedType(T))