`DICT.ML`;
%JJS - several functions moved to LIB.ML%

% A simple dictionary %
% Author:  John Scott %
% Derived from a more sophisticated "hash table" facility by KEVIN %


let type 'a Dictionary <=> (|
    Size            : int;
    DefaultVal      : string -> 'a;
    DuplicateChoice : string # 'a # 'a -> 'a;
    KeyPrint        : string -> .;
    ValPrint        : 'a -> .;
    Table           : ((string # ('a ref)) list) array |)

with {
{ { rec searchForMatch(key:string,l) = 
    if null(l) then inr()
    else if fst(hd(l))=key then inl(snd(hd(l)))
    else searchForMatch(key,tl(l)) }

ins { AddToDictionary(Dictionary,Key,Value) =
    let (| Size; DefaultVal=_; DuplicateChoice; KeyPrint=_; ValPrint=_; Table
            |) = repDictionary(Dictionary)
    enc index = tokhash(Key,Size) + 1
    enc searchList = Table sub index
    enc r = searchForMatch(Key,searchList)
    in
        if isl(r) then outl(r) := DuplicateChoice(Key,!outl(r),Value)
        else update(Table,index,(Key,(ref Value))::searchList)

and FetchFromDictionary(Dictionary,Key) =
    let (| Size; DefaultVal; DuplicateChoice=_; KeyPrint=_; ValPrint=_; Table
            |) = repDictionary(Dictionary)
    enc searchList = Table sub (tokhash(Key,Size) + 1) 
    enc r = searchForMatch(Key,searchList)
    in
        if isl(r) then !outl(r)
        else DefaultVal(Key) } }

enc { { rec removeMatch(Key:string,l) =
    if null(l) then []
    else if fst(hd(l))=Key then tl(l) % This was "removeMatch(Key,tl(l))" %
    else hd(l)::removeMatch(Key,tl(l)) }

ins RemoveFromDictionary(Dictionary,Key) =
    let (| Size; DefaultVal=_; DuplicateChoice=_; KeyPrint=_; ValPrint=_; Table
            |) = repDictionary(Dictionary)
    enc index = tokhash(Key,Size) + 1
    enc searchList = Table sub index
    in update(Table, index, removeMatch(Key,searchList)) }

enc ClearDictionary(Dictionary) =
    let (| Size; DefaultVal=_; DuplicateChoice=_; KeyPrint=_; ValPrint=_; Table
            |) = repDictionary(Dictionary)
    in
        AppInt (\index. update(Table,index,[])) (1,Size)

enc AppDictionary f Dictionary =
    AppArray (\l. app (\k,v.f(k,!v)) l) (repDictionary(Dictionary).Table)

enc PrintDictionary Dictionary =
    let (| Size=_; DefaultVal=_; DuplicateChoice=_; KeyPrint; ValPrint; Table=_
            |) = repDictionary(Dictionary)
    in
        AppDictionary 
            (\(t,l). (
                outtok(`entry `); KeyPrint(t);
                outtok(` = `); ValPrint(l); newline(1) ))
            Dictionary

enc NewDictionary(Size,DefaultVal,DuplicateChoice,KeyPrint,ValPrint) =
    absDictionary(| Size; DefaultVal; DuplicateChoice; KeyPrint; ValPrint;
        Table = array(Size,[]) |)

enc CopyFromDictionary( oldDictionary, EntriesRequired, Size, DefaultVal,
        DuplicateChoice, KeyPrint, ValPrint ) =
    let newDictionary =
        NewDictionary(Size,DefaultVal,DuplicateChoice,KeyPrint,ValPrint)
    in (
        AppDictionary 
            ( \k,v.
                if null(EntriesRequired) Or MemberTok(k,EntriesRequired)
                then AddToDictionary(newDictionary, k, v)
                else () ) 
            oldDictionary;
        newDictionary )
};

