BiRelVectors.Mesa
Last tweaked by Mike Spreitzer on December 18, 1987 4:03:50 pm PST
DIRECTORY AbSets, BiRelBasics, BiRels, IntStuff, SetBasics;
BiRelVectors: CEDAR PROGRAM
IMPORTS AbSets, BiRelBasics, BiRels, IntStuff, SetBasics
EXPORTS BiRels
=
BEGIN OPEN IntStuff, SetBasics, Sets:AbSets, Sets, BiRelBasics, BiRels;
Simple: TYPE ~ REF SimplePrivate;
SimplePrivate: TYPE ~ RECORD [
right: Space,
bounds: IntInterval,
leftDense, domFixed: BOOL,
d: INT,
vals: SimpleElts,
size, freezeCount: INT ← 0];
elt i is stored in vals[i-d]. Thus, there is storage for elts [d .. d+vals.size). Storage cells not corresponding to domain elts have noValue in them.
SimpleElts: TYPE ~ REF SimpleEltsPrivate;
SimpleEltsPrivate: TYPE ~ RECORD [vals: SEQUENCE size: NATURAL OF Value];
CreateSimpleCopy: PUBLIC PROC [of: IntFn, bounds: IntInterval ← [], oneToOne, dense, domainFixed: RelBool ← SAME, rightSpace: Space ← NIL] RETURNS [IntFn] ~ {
realBounds: IntInterval ~ of.GetIntDom.Intersect[bounds];
realOneToOne: BOOL ~ oneToOne.RelativizeBool[of.Functional[][rightToLeft]];
realDense: BOOL ~ dense.RelativizeBool[of.IsDense[always, left]];
realDomainFixed: BOOL ~ domainFixed.RelativizeBool[of.SideFixed[left]];
realSpace: Space ~ IF rightSpace#NIL THEN rightSpace ELSE of.Spaces[][right];
vals: SimpleElts ~ NEW [SimpleEltsPrivate[realBounds.Length.EN]];
simple: Simple ~ NEW [SimplePrivate ← [realSpace, realBounds, realDense, realDomainFixed, realBounds.min, vals, of.Size[].EN]];
FOR i: INT IN [realBounds.min .. realBounds.max] DO {
mv: MaybeValue ~ of.ApplyI[i];
vals[i-simple.d] ← mv.it;
}ENDLOOP;
RETURN [[simpleClasses[realOneToOne][realDense][realDomainFixed][variable], simple]]};
CreateSimple: PUBLIC PROC [bounds: IntInterval ← [0, -1], val: Value ← noValue, oneToOne, dense, domainFixed: BOOLFALSE, rightSpace: Space ← refs] RETURNS [IntFn] ~ {
vals: SimpleElts ~ NEW [SimpleEltsPrivate[bounds.Length.EN]];
simple: Simple ~ NEW [SimplePrivate ← [rightSpace, bounds, dense, domainFixed, bounds.min, vals, bounds.Length.EN]];
FOR i: NATURAL IN [0 .. vals.size) DO vals[i] ← val ENDLOOP;
IF val=noValue THEN {
simple.bounds ← simple.bounds.ClipTop[simple.bounds.min];
simple.size ← 0};
RETURN [[simpleClasses[oneToOne][dense][domainFixed][variable], simple]]};
SimpleClasses: TYPE ~ ARRAY --oneToOne--BOOL OF ARRAY --leftDense--BOOL OF ARRAY --domainFixed--BOOL OF ARRAY Mutability OF BiRelClass;
simpleClasses: REF SimpleClasses ~ NEW [SimpleClasses];
SimplePrimitive: PROC [br: BiRel, op: ATOM, arg1, arg2: REF ANY] RETURNS [PrimitiveAnswer] ~ {
simple: Simple ~ NARROW[br.data];
SELECT op FROM
$Apply => {dir: Direction ~ ToDir[arg1];
RETURN [IF dir=leftToRight THEN yes ELSE no]};
$ScanRestriction, $GetBounds => {ro: RelOrder ~ ToRO[arg2];
RETURN [IF ro.first#left AND ro.sub[ro.first]#no THEN no ELSE yes]};
$RestrictionSize => {sets: RefSetPair ~ ToSets[arg1];
RETURN [IF sets^=ALL[nilSet] THEN yes ELSE no]};
ENDCASE => RETURN [pass]};
SimpleApply: PROC [br: BiRel, v: Value, dir: Direction] RETURNS [MaybeValue] ~ {
simple: Simple ~ NARROW[br.data];
IF br.MutabilityOf=constant AND simple.freezeCount=0 THEN Complain[br, unfrozen];
IF dir=rightToLeft THEN RETURN DefaultApply[br, v, dir];
{i: INT ~ v.VI;
w: Value ~ IF simple.bounds.Contains[i] THEN simple.vals[i-simple.d] ELSE noValue;
RETURN [[w#noValue, w]]}};
SimpleScanRestriction: PROC [br: BiRel, sets: SetPair, Test: Tester, ro: RelOrder] RETURNS [MaybePair] ~ {
simple: Simple ~ NARROW[br.data];
IF br.MutabilityOf=constant AND simple.freezeCount=0 THEN Complain[br, unfrozen];
IF ro.first#left AND ro.sub[ro.first]#no THEN RETURN DefaultScanRestriction[br, sets, Test, ro];
{vals: SimpleElts ~ simple.vals;
left: Set ~ sets[left];
right: Set ~ sets[right];
leftTested: BOOL ~ left=nilSet OR left.GoodImpl[$QuaIntInterval];
lb: MaybeIntInterval ~ IF left#nilSet AND leftTested THEN left.QuaIntInterval ELSE [TRUE, []];
scanBounds: IntInterval ~ simple.bounds.Intersect[IF lb.found THEN lb.it ELSE []];
rn: BOOL ~ right=nilSet;
ld: BOOL ~ leftTested AND lb.found;
IF ro.sub[left]=bwd
THEN FOR i: INT DECREASING IN [scanBounds.min .. scanBounds.max] DO
pair: Pair ~ [IV[i], simple.vals[i-simple.d]];
IF pair[right]#noValue AND (ld OR left.HasMember[IV[i]]) AND (rn OR right.HasMember[pair[right]]) AND Test[pair] THEN RETURN [[TRUE, pair]];
ENDLOOP
ELSE FOR i: INT IN [scanBounds.min .. scanBounds.max] DO
pair: Pair ~ [IV[i], simple.vals[i-simple.d]];
IF pair[right]#noValue AND (ld OR left.HasMember[IV[i]]) AND (rn OR right.HasMember[pair[right]]) AND Test[pair] THEN RETURN [[TRUE, pair]];
ENDLOOP;
RETURN [noMaybePair]}};
SimpleRestrictionSize: PROC [br: BiRel, sets: SetPair, limit: EINT] RETURNS [EINT] ~ {
simple: Simple ~ NARROW[br.data];
IF sets # ALL[nilSet] THEN RETURN DefaultRestrictionSize[br, sets, limit];
RETURN [IE[simple.size]]};
SimpleGetBounds: PROC [br: BiRel, want: EndBools, ro: RelOrder] RETURNS [MaybePairInterval] ~ {
simple: Simple ~ NARROW[br.data];
IF br.MutabilityOf=constant AND simple.freezeCount=0 THEN Complain[br, unfrozen];
IF ro.first#left AND ro.sub[left]#no THEN RETURN DefaultGetBounds[br, want, ro];
IF simple.bounds.Empty THEN RETURN [[FALSE, [
min: [IV[simple.bounds.min], noValue],
max: [IV[simple.bounds.max], noValue]] ]];
{pi: PairInterval ~ [min: [IV[simple.bounds.min], simple.vals[simple.bounds.min-simple.d]], max: [IV[simple.bounds.max], simple.vals[simple.bounds.max-simple.d]]];
RETURN [[TRUE, IF ro.sub[left]#bwd THEN pi ELSE RevPI[pi] ]]}};
SimpleCopy: PROC [br: BiRel] RETURNS [VarBiRel] ~ {
simple: Simple ~ NARROW[br.data];
v1: SimpleElts ~ simple.vals;
IF br.MutabilityOf=constant AND simple.freezeCount=0 THEN Complain[br, unfrozen];
{v2: SimpleElts ~ NEW [SimpleEltsPrivate[v1.size]];
s2: Simple ~ NEW [SimplePrivate ← simple^];
s2.vals ← v2;
s2.freezeCount ← 0;
FOR i: NATURAL IN [0 .. v2.size) DO v2[i] ← v1[i] ENDLOOP;
RETURN AsVar[[simpleClasses [br.Functional[][rightToLeft]] [simple.leftDense] [simple.domFixed] [variable], s2]]}};
SimpleFreeze: PROC [br: BiRel] RETURNS [ConstBiRel] ~ {
simple: Simple ~ NARROW[br.data];
IF br.MutabilityOf#variable THEN Complain[br, notVariable];
simple.freezeCount ← simple.freezeCount + 1;
RETURN AsConst[[
simpleClasses [br.IsOneToOne] [simple.leftDense] [br.SideFixed[left]] [constant],
simple]];
};
SimpleThaw: PROC [br: BiRel] ~ {
simple: Simple ~ NARROW[br.data];
IF br.MutabilityOf#variable THEN Complain[br, notVariable];
IF simple.freezeCount<=0 THEN Complain[br, "too many thaws"];
simple.freezeCount ← simple.freezeCount-1;
RETURN};
SimpleAddSet: PROC [br, other: BiRel, if: IfHadPair] RETURNS [some: HadSetPair] ~ {
simple: Simple ~ NARROW[br.data];
right: Space ~ simple.right;
invSearch: BOOL ~ br.Functional[][rightToLeft];
urSize: INT ~ simple.size;
bounds: IntInterval;
d: INT;
vals: SimpleElts;
expansionCount: NATURAL ← 0;
Per: PROC [pair: Pair] RETURNS [BOOL] ~ {
i: INT ~ pair[left].VI;
news: Had ← different;
IF invSearch THEN FOR j: INT IN [bounds.min-d .. bounds.max-d] DO
IF vals[j]#noValue AND right.SEqual[vals[j], pair[right]] THEN
{some[rightToLeft][IF i=j THEN same ELSE different] ← TRUE; EXIT};
REPEAT FINISHED => some[rightToLeft][none] ← TRUE;
ENDLOOP;
IF bounds.Contains[i] THEN {
old: Value ~ vals[i-d];
IF old=noValue THEN {
news ← none;
simple.size ← simple.size+1;
}
ELSE IF right.SEqual[pair[right], old] THEN news ← same
}
ELSE IF simple.domFixed THEN br.Complain[fixedSide, LIST[AV[$left]]]
ELSE {
de: NATURAL ~ EnsureContains[simple, [i, i]];
IF de=0 THEN ERROR;
expansionCount ← expansionCount + de;
simple.size ← simple.size+1;
bounds ← simple.bounds; d ← simple.d; vals ← simple.vals; news ← none};
vals[i-d] ← pair[right];
some[leftToRight][news] ← TRUE;
RETURN [FALSE]};
IF br.MutabilityOf # variable THEN br.Complain[notVariable];
IF simple.freezeCount#0 THEN br.Complain[frozen];
some ← ALL[ALL[FALSE]];
IF other.QualityOf[$GetIntDom] >= goodDefault THEN expansionCount ← EnsureContains[simple, other.GetIntDom[]];
bounds ← simple.bounds; d ← simple.d; vals ← simple.vals;
[] ← other.Scan[Per];
{newCount: NATURAL ~ simple.size - urSize;
IF simple.leftDense AND newCount<expansionCount THEN br.Complain[denseSide, LIST[AV[$left]]];
IF newCount#0 THEN some[leftToRight][none] ← TRUE;
RETURN}};
EnsureContains: PROC [simple: Simple, bounds: IntInterval] RETURNS [expansionCount: NATURAL] ~ {
IF bounds.min >= simple.bounds.min AND bounds.max <= simple.bounds.max THEN RETURN [0];
{oldVals: SimpleElts ~ simple.vals;
oldSize: NATURAL ~ oldVals.size;
oldBounds: IntInterval ~ simple.bounds;
newBounds: IntInterval ~ simple.bounds.MBI[bounds];
newLen: NATURAL ~ newBounds.Length.EN;
oldD: INT ~ simple.d;
expansionCount ← newLen - oldBounds.Length.EN;
simple.bounds ← newBounds;
IF newBounds.min >= oldD AND newBounds.max <= oldD+(oldSize-1) THEN RETURN;
IF newLen <= oldSize THEN {
newPad: INT ~ (oldSize - newLen)/2;
newD: INT ~ ISub[newBounds.min, newPad].ClipI;
IF newD > oldD THEN {
FOR i: INT IN [oldBounds.min .. oldBounds.max] DO
oldVals[i-newD] ← oldVals[i-oldD];
ENDLOOP;
IF NOT oldBounds.Empty THEN FOR i: INT IN (oldBounds.max-newD .. oldBounds.max-oldD] DO
oldVals[i] ← noValue;
ENDLOOP;
};
IF newD < oldD THEN {
FOR i: INT DECREASING IN [oldBounds.min .. oldBounds.max] DO
oldVals[i-newD] ← oldVals[i-oldD];
ENDLOOP;
IF NOT oldBounds.Empty THEN FOR i: INT IN [oldBounds.min-oldD .. oldBounds.min-newD) DO
oldVals[i] ← noValue;
ENDLOOP;
};
simple.d ← newD;
RETURN};
{newSize: NATURAL ~ MIN[INT[NATURAL.LAST], MAX[newLen, INT[oldSize]*2]];
newVals: SimpleElts ~ NEW [SimpleEltsPrivate[newSize]];
newPad: INT ~ (newSize - newLen)/2;
newD: INT ~ newBounds.min - newPad;
IF oldBounds.Empty THEN {
FOR i: INT IN [0 .. newSize) DO newVals[i] ← noValue ENDLOOP;
}
ELSE {
FOR i: INT IN [0 .. oldBounds.min-newD) DO newVals[i] ← noValue ENDLOOP;
FOR i: INT IN [oldBounds.min .. oldBounds.max] DO newVals[i-newD] ← oldVals[i-oldD] ENDLOOP;
FOR i: INT IN (oldBounds.max-newD .. newSize) DO newVals[i] ← noValue ENDLOOP;
};
simple.d ← newD;
simple.vals ← newVals;
RETURN}}};
SimpleDenseRemSet: PROC [br, other: BiRel] RETURNS [some: HadSetPair ← []] ~ {
simple: Simple ~ NARROW[br.data];
vals: SimpleElts ~ simple.vals;
right: Space ~ simple.right;
urSize: INT ~ simple.size;
oldBounds: IntInterval ~ simple.bounds;
otherBounds: IntInterval ~ other.GetIntDom[];
scanBounds: IntInterval ~ oldBounds.Intersect[otherBounds];
mustKeep: IntInterval ← anEmptyInterval;
may: IntInterval ← oldBounds;
Per: PROC [pair: Pair] RETURNS [BOOL] ~ {
i: INT ~ pair[left].VI;
w: Value ~ vals[i-simple.d];
hadIt: BOOL ~ right.SEqual[pair[right], w];
IF hadIt THEN {
IF simple.domFixed THEN br.Complain[fixedSide, LIST[AV[$left]]]
ELSE IF mustKeep.Contains[i] THEN br.Complain[denseSide, LIST[AV[$left]]]
ELSE IF may.Contains[i] THEN {
SELECT i FROM
< mustKeep.min => may.min ← i+1;
> mustKeep.max => may.max ← i-1;
ENDCASE => ERROR;
};
vals[i-simple.d] ← noValue;
some[leftToRight][same] ← TRUE; simple.size ← simple.size - 1}
ELSE {
IF NOT may.Contains[i] THEN br.Complain[denseSide, LIST[AV[$left]]]
ELSE IF NOT mustKeep.Contains[i] THEN mustKeep ← [min: MIN[mustKeep.min, i], max: MAX[mustKeep.max, i]];
some[leftToRight][different] ← TRUE};
RETURN [FALSE]};
IF br.MutabilityOf # variable THEN br.Complain[notVariable];
IF simple.freezeCount#0 THEN br.Complain[frozen];
some[leftToRight][none] ← scanBounds#otherBounds;
IF br.Functional[][rightToLeft] THEN some[rightToLeft] ← Has[br, other, [FALSE, TRUE]][rightToLeft];
[] ← other.ScanHalfRestriction[IIAsSet[scanBounds], Per];
simple.bounds ← may;
simple.d ← simple.d - oldBounds.min + simple.bounds.min;
IF may.Length.AddI[urSize-simple.size] # oldBounds.Length THEN br.Complain[denseSide, LIST[AV[$left]]];
RETURN};
SimpleSparseRemSet: PROC [br, other: BiRel] RETURNS [some: HadSetPair ← []] ~ {
simple: Simple ~ NARROW[br.data];
vals: SimpleElts ~ simple.vals;
right: Space ~ simple.right;
oldBounds: IntInterval ~ simple.bounds;
otherBounds: IntInterval ~ other.GetIntDom[];
scanBounds: IntInterval ~ otherBounds.Intersect[oldBounds];
rebound: BOOLFALSE;
Per: PROC [pair: Pair] RETURNS [pass: BOOLFALSE] ~ {
i: INT ~ pair[left].VI;
w: Value ~ vals[i-simple.d];
notno: BOOL ~ w#noValue;
hadIt: BOOL ~ notno AND right.SEqual[pair[right], w];
IF hadIt THEN {
IF simple.domFixed THEN br.Complain[fixedSide, LIST[AV[$left]]];
IF i=oldBounds.min OR i=oldBounds.max THEN rebound ← TRUE;
vals[i-simple.d] ← noValue;
simple.size ← simple.size - 1;
some[leftToRight][same] ← TRUE}
ELSE some[leftToRight][IF notno THEN different ELSE none] ← TRUE;
};
IF br.MutabilityOf # variable THEN br.Complain[notVariable];
IF simple.freezeCount#0 THEN br.Complain[frozen];
some[leftToRight][none] ← scanBounds#otherBounds;
IF br.Functional[][rightToLeft] THEN some[rightToLeft] ← Has[br, other, [FALSE, TRUE]][rightToLeft];
[] ← other.ScanHalfRestriction[IIAsSet[scanBounds], Per];
IF rebound THEN FixBounds[br, simple];
RETURN};
FixBounds: PROC [br: BiRel, simple: Simple] ~ {
vals: SimpleElts ~ simple.vals;
d: INT ~ simple.d;
oldBounds: IntInterval ~ simple.bounds;
newBounds: IntInterval ← oldBounds;
WHILE newBounds.min<=newBounds.max AND vals[newBounds.min-d]=noValue DO newBounds ← newBounds.ClipBot[newBounds.min] ENDLOOP;
WHILE newBounds.min<=newBounds.max AND vals[newBounds.max-d]=noValue DO newBounds ← newBounds.ClipTop[newBounds.max] ENDLOOP;
simple.bounds ← newBounds;
IF NOT (oldBounds.Empty OR newBounds.Empty) THEN simple.d ← simple.d - simple.bounds.min + newBounds.min;
RETURN};
LeftDelete: PROC [simple: Simple, where: IntInterval] ~ {
in: IntInterval ~ where.Intersect[simple.bounds];
IF in.Empty THEN RETURN;
FOR i: INT IN [in.min-simple.d .. in.max-simple.d] DO
IF simple.vals[i]#noValue THEN {
simple.vals[i] ← noValue;
simple.size ← simple.size-1};
ENDLOOP;
IF where.min > simple.bounds.min
THEN IF where.max < simple.bounds.max
THEN NULL
ELSE simple.bounds.max ← where.min-1
ELSE IF where.max < simple.bounds.max
THEN simple.bounds.min ← where.max+1
ELSE simple.bounds ← anEmptyInterval;
RETURN};
SimpleReplaceMe: PROC [br, with: BiRel, where: IntInterval] ~ {
simple: Simple ~ NARROW[br.data];
clip: IntInterval ~ with.GetIntDom[];
clipLen: EINT ~ clip.Length;
whereLen: EINT ~ where.Length;
tailShift: EINT ~ clipLen.Sub[whereLen];
insertShift: EINT ~ ISub[where.min, clip.min];
oldBounds: IntInterval ~ simple.bounds;
insertBoundsEst: IntInterval ~ clip.ClipShiftInterval[insertShift];
beforeTail: INT ~ IF where.Empty THEN where.min-1 ELSE where.max;
bounds: IntInterval ← anEmptyInterval;
newBoundsEst, headNeed, tailNeed: IntInterval;
AddStuff: PROC [new: IntInterval] ~ {bounds ← bounds.MBI[new]};
AddPair: PROC [pair: Pair] RETURNS [BOOL] ~ {
i: INT ~ insertShift.AddI[pair[left].VI].EI;
[] ← EnsureContains[simple, [i, i]];
AddStuff[[i, i]]; simple.size ← simple.size + 1;
simple.vals[i-simple.d] ← pair[right];
RETURN [FALSE]};
IF br.MutabilityOf # variable THEN br.Complain[notVariable];
IF simple.freezeCount#0 THEN br.Complain[frozen];
SELECT TRUE FROM
oldBounds.max < where.min => {headNeed ← newBoundsEst ← oldBounds; tailNeed ← anEmptyInterval};
oldBounds.min > beforeTail => {tailNeed ← newBoundsEst ← oldBounds.ShiftInterval[tailShift]; headNeed ← anEmptyInterval};
ENDCASE => {
newBoundsEst ← [
min: MIN[oldBounds.min, where.min],
max: tailShift.AddI[MAX[oldBounds.max, where.max]].ClipI];
headNeed ← newBoundsEst.ClipTop[where.min];
tailNeed ← newBoundsEst.ClipBot[tailShift.AddI[beforeTail].ClipI]};
[] ← EnsureContains[simple, tailNeed];
AddStuff[headNeed];
AddStuff[tailNeed];
IF NOT tailNeed.Empty THEN SELECT tailShift.Sgn[] FROM
<0 => {
FOR i: INT IN [tailNeed.min-simple.d .. tailNeed.max-simple.d] DO
j: INT ~ tailShift.SubFromI[i].EI;
IF simple.vals[i]=noValue THEN simple.size ← simple.size-1;
simple.vals[i] ← simple.vals[j]; simple.vals[j] ← noValue;
ENDLOOP;
};
>0 => {
olds: IntInterval ~ oldBounds.ClipBot[insertBoundsEst.max].ClipTop[tailNeed.min];
FOR i: INT DECREASING IN [tailNeed.min .. tailNeed.max] DO
j: INT ~ tailShift.SubFromI[i].EI;
simple.vals[i-simple.d] ← simple.vals[j-simple.d];
ENDLOOP;
FOR i: INT IN [olds.min .. olds.max] DO
simple.vals[i-simple.d] ← noValue;
ENDLOOP;
};
=0 => NULL;
ENDCASE => ERROR;
LeftDelete[simple, insertBoundsEst];
{midSize: INT ~ simple.size;
[] ← with.Scan[AddPair];
IF simple.leftDense AND headNeed.Length.Add[tailNeed.Length].AddI[simple.size-midSize] # bounds.Length THEN br.Complain[denseSide, LIST[AV[$left]]];
IF simple.domFixed AND bounds#oldBounds THEN br.Complain[fixedSide, LIST[AV[$left]]];
simple.bounds ← bounds;
IF NOT (bounds.Empty OR oldBounds.Empty) THEN simple.d ← simple.d-oldBounds.min+simple.bounds.min;
RETURN}};
SimpleShiftAndClipMe: PROC [br: BiRel, shift: EINT, clip: IntInterval] ~ {
simple: Simple ~ NARROW[br.data];
unshifted: IntInterval ~ simple.bounds.Intersect[clip];
newBounds: IntInterval ~ unshifted.ClipShiftInterval[shift];
IF br.MutabilityOf#variable THEN br.Complain[notVariable];
IF simple.freezeCount#0 THEN br.Complain[frozen];
IF simple.domFixed AND newBounds#simple.bounds THEN br.Complain[fixedSide, LIST[AV[$left]]];
FOR i: INT IN [simple.bounds.min-simple.d .. unshifted.min-simple.d) DO
IF simple.vals[i]#noValue THEN {simple.vals[i] ← noValue; simple.size ← simple.size-1};
ENDLOOP;
FOR i: INT IN (unshifted.max-simple.d .. simple.bounds.max-simple.d] DO
IF simple.vals[i]#noValue THEN {simple.vals[i] ← noValue; simple.size ← simple.size-1};
ENDLOOP;
simple.d ← shift.AddI[simple.d].EI;
simple.bounds ← newBounds;
RETURN};
SimpleSpaces: PROC [br: BiRel] RETURNS [SpacePair] ~ {
simple: Simple ~ NARROW[br.data];
RETURN [[ints, simple.right]]};
SimpleIsDense: PROC [br: BiRel, when: When, side: Side] RETURNS [BOOL] ~ {
simple: Simple ~ NARROW[br.data];
RETURN [side=left AND simple.leftDense]};
SimpleSideFixed: PROC [br: BiRel, side: Side] RETURNS [BOOL] ~ {
simple: Simple ~ NARROW[br.data];
RETURN [br.MutabilityOf=constant OR (side=left AND simple.domFixed)]};
Start: PROC ~ {
FOR isOneToOne: BOOL IN BOOL DO FOR dense: BOOL IN BOOL DO FOR domainFixed: BOOL IN BOOL DO FOR mutability: Mutability IN Mutability DO
simpleClasses[isOneToOne][dense][domainFixed][mutability] ← CreateClass[
cp: [
Primitive: SimplePrimitive,
Apply: SimpleApply,
ScanRestriction: SimpleScanRestriction,
RestrictionSize: SimpleRestrictionSize,
GetBounds: SimpleGetBounds,
Copy: SimpleCopy,
Freeze: SimpleFreeze,
Thaw: SimpleThaw,
AddSet: SimpleAddSet,
RemSet: IF dense THEN SimpleDenseRemSet ELSE SimpleSparseRemSet,
ReplaceMe: SimpleReplaceMe,
ShiftAndClipMe: SimpleShiftAndClipMe,
Spaces: SimpleSpaces,
IsDense: SimpleIsDense,
SideFixed: SimpleSideFixed,
functional: [TRUE, isOneToOne],
mutability: mutability
],
dirable: [TRUE, TRUE]
];
ENDLOOP ENDLOOP ENDLOOP ENDLOOP;
};
Start[];
END.