OneToOneImpl:
CEDAR
PROGRAM
IMPORTS OneToOne, RefTab
EXPORTS OneToOne
= {OPEN OneToOne;
Contradiction: PUBLIC ERROR [oto: OneToOne, a, b: REF ANY] = CODE;
CreateVanillaOneToOne:
PUBLIC
PROC [hashA, hashB: RefTab.HashProc ←
NIL, compareA, compareB: RefTab.EqualProc ←
NIL]
RETURNS [oto: OneToOne] = {
oto ← NEW [OneToOnePrivate ← [HashedEnumerate, HashedAssociate, HashedMap, NEW [HashOneToOnePrivate ← [RefTab.Create[equal: compareA, hash: hashA], RefTab.Create[equal: compareB, hash: hashB]]]]];
};
HashOneToOne: TYPE = REF HashOneToOnePrivate;
HashOneToOnePrivate:
TYPE =
RECORD [
forward, backward: RefTab.Ref
];
HashedEnumerate:
PROC [oto: OneToOne,
Consume:
PROC [a, b:
REF
ANY]] = {
hoto: HashOneToOne = NARROW[oto.data];
PerPair:
PROC [key, val:
REF
ANY]
RETURNS [quit:
BOOL ←
FALSE]
--RefTab.EachPairAction-- = {
Consume[key, val];
};
[] ← hoto.forward.Pairs[PerPair];
};
HashedAssociate:
PROC [oto: OneToOne, a, b:
REF
ANY] = {
hoto: HashOneToOne = NARROW[oto.data];
IF a=NIL OR b=NIL OR NOT (hoto.forward.Insert[a, b] AND hoto.backward.Insert[b, a]) THEN ERROR Contradiction[oto, a, b];
};
HashedMap:
PROC [oto: OneToOne, from:
REF
ANY, forward:
BOOL ←
TRUE]
RETURNS [to:
REF
ANY] = {
hoto: HashOneToOne = NARROW[oto.data];
to ← (IF forward THEN hoto.forward ELSE hoto.backward).Fetch[from].val;
};
id: PUBLIC OneToOne = NEW [OneToOnePrivate ← [NIL, NIL, MapId]];
MapId: PROC [oto: OneToOne, from: REF ANY, forward: BOOL ← TRUE] RETURNS [REF ANY] = {RETURN [from]};
Reverse:
PUBLIC
PROC [fwd: OneToOne]
RETURNS [rev: OneToOne] = {
rev ← NEW [OneToOnePrivate ← [ReversedEnumerate, ReversedAssociate, ReversedMap, fwd]];
};
ReversedEnumerate:
PROC [oto: OneToOne,
Consume:
PROC [a, b:
REF
ANY]] = {
fwd: OneToOne = NARROW[oto.data];
Reverse: PROC [a, b: REF ANY] = {Consume[b, a]};
fwd.Enumerate[Reverse];
};
ReversedAssociate:
PROC [oto: OneToOne, a, b:
REF
ANY] = {
fwd: OneToOne = NARROW[oto.data];
fwd.Associate[b, a]};
ReversedMap:
PROC [oto: OneToOne, from:
REF
ANY, forward:
BOOL ←
TRUE]
RETURNS [to:
REF
ANY] = {
fwd: OneToOne = NARROW[oto.data];
to ← fwd.Map[from, NOT forward];
};
Triplate:
PUBLIC
PROC [inward, inner, outward: OneToOne]
RETURNS [outer: OneToOne] = {
t: Triplator = NEW [TriplatorPrivate ← [inward, inner, outward]];
outer ← NEW [OneToOnePrivate ← [TriplatedEnumerate, TriplatedAssociate, TriplatedMap, t]];
};
Triplator: TYPE = REF TriplatorPrivate;
TriplatorPrivate: TYPE = RECORD [inward, inner, outward: OneToOne];
TriplatedEnumerate:
PROC [oto: OneToOne,
Consume:
PROC [a, b:
REF
ANY]] = {
t: Triplator = NARROW[oto.data];
Triplate:
PROC [a, b:
REF
ANY] = {
Consume[t.inward.Map[a, FALSE], t.outward.Map[b, TRUE]];
};
t.inner.Enumerate[Triplate];
};
TriplatedAssociate:
PROC [oto: OneToOne, a, b:
REF
ANY] = {
t: Triplator = NARROW[oto.data];
t.inner.Associate[t.inward.Map[a, TRUE], t.outward.Map[b, FALSE]];
};
TriplatedMap:
PROC [oto: OneToOne, from:
REF
ANY, forward:
BOOL ←
TRUE]
RETURNS [to:
REF
ANY] = {
t: Triplator = NARROW[oto.data];
to ←
IF forward
THEN t.outward.Map[t.inner.Map[t.inward.Map[from, TRUE], TRUE], TRUE]
ELSE t.inward.Map[t.inner.Map[t.outward.Map[from, FALSE], FALSE], FALSE];
};
}.