DIRECTORY Basics, Collections, IntFunctions, IntStuff, PairCollections, List; StdIntFunctions1: CEDAR PROGRAM IMPORTS Collections, IntFunctions, IntStuff, PairCollections, List EXPORTS IntFunctions = BEGIN OPEN PCs:PairCollections, Colls:Collections, Ints:IntStuff, Collections, PairCollections, IntStuff, IntFunctions; emptyClass: IntFnClass ~ CreateClass[[ HasPair: EmptyHasPair, Apply: EmptyApply, InvApply: EmptyInvApply, Scan: EmptyScan, Extremum: EmptyExtremum, Get3: EmptyGet3, Index: EmptyIndex, Size: EmptySize, GetBounds: EmptyGetBounds, RightCollection: EmptyRightCollection, CurRange: EmptyCurRange, isOneToOne: TRUE, isDense: TRUE, ordered: TRUE, mutability: constant, domainFixed: TRUE], ALL[TRUE]]; empty: PUBLIC ConstIntFn ~ AsConst[[emptyClass, NIL]]; EmptyHasPair: PROC [fn: IntFn, pair: IVPair] RETURNS [BOOL] ~ {RETURN [FALSE]}; EmptyApply: PROC [fn: IntFn, i: INT] RETURNS [MaybeValue] ~ {RETURN [noMaybe]}; EmptyInvApply: PROC [fn: IntFn, v: Value] RETURNS [MaybeInt] ~ {RETURN [noInt]}; EmptyScan: PROC [fn: IntFn, Test: Tester, left: Interval, right: Collection, bkwd: BOOL] RETURNS [MaybePair] ~ {RETURN [noMaybePair]}; EmptyExtremum: PROC [fn: IntFn, bkwd, remove: BOOL] RETURNS [MaybePair] ~ {RETURN [noMaybePair]}; EmptyGet3: PROC [fn: IntFn, pair: IVPair] RETURNS [prev, same, next: MaybePair] ~ {RETURN [noMaybePair, noMaybePair, noMaybePair]}; EmptyIndex: PROC [fn, goal: IntFn, bounds: Interval, bkwd: BOOL] RETURNS [MaybeInt] ~ {RETURN [noInt]}; EmptySize: PROC [fn: IntFn, left: Interval, right: Collection, limit: LNAT] RETURNS [LNAT] ~ {RETURN [0]}; EmptyGetBounds: PROC [fn: IntFn] RETURNS [Interval] ~ {RETURN [anEmptyInterval]}; EmptyRightCollection: PROC [fn: IntFn] RETURNS [UWColl] ~ {RETURN [emptySet]}; EmptyCurRange: PROC [fn: IntFn] RETURNS [ConstSet] ~ {RETURN [emptySet]}; Singleton: TYPE ~ REF SingletonPrivate; SingletonPrivate: TYPE ~ RECORD [ pair: IVPair, right: Space ]; CreateSingleton: PUBLIC PROC [pair: IVPair, right: Space] RETURNS [ConstIntFn] ~ { s: Singleton ~ NEW [SingletonPrivate _ [pair, right]]; RETURN AsConst[[singletonClass, s]]}; singletonClass: IntFnClass ~ CreateClass[[ HasPair: SingletonHasPair, Apply: SingletonApply, InvApply: SingletonInvApply, Scan: SingletonScan, Extremum: SingletonExtremum, Get3: SingletonGet3, Size: SingletonSize, GetBounds: SingletonGetBounds, CurRange: SingletonCurRange, RightSpace: SingletonRightSpace, isOneToOne: TRUE, isDense: TRUE, ordered: TRUE, mutability: constant, domainFixed: TRUE], ALL[TRUE]]; SingletonHasPair: PROC [fn: IntFn, pair: IVPair] RETURNS [BOOL] ~ { s: Singleton ~ NARROW[fn.data]; RETURN [s.pair.left=pair.left AND s.right.SpaceEqual[s.pair.right, pair.right]]}; SingletonApply: PROC [fn: IntFn, i: INT] RETURNS [MaybeValue] ~ { s: Singleton ~ NARROW[fn.data]; RETURN [IF s.pair.left=i THEN [TRUE, s.pair.right] ELSE noMaybe]}; SingletonInvApply: PROC [fn: IntFn, v: Value] RETURNS [MaybeInt] ~ { s: Singleton ~ NARROW[fn.data]; RETURN [IF s.right.SpaceEqual[s.pair.right, v] THEN [TRUE, s.pair.left] ELSE noInt]}; SingletonScan: PROC [fn: IntFn, Test: Tester, left: Interval, right: Collection, bkwd: BOOL] RETURNS [MaybePair] ~ { s: Singleton ~ NARROW[fn.data]; RETURN [IF Test[s.pair] THEN [TRUE, s.pair] ELSE noMaybePair]}; SingletonExtremum: PROC [fn: IntFn, bkwd, remove: BOOL] RETURNS [MaybePair] ~ { s: Singleton ~ NARROW[fn.data]; IF remove THEN fn.Complain[notVariable]; RETURN [[TRUE, s.pair]]}; SingletonGet3: PROC [fn: IntFn, pair: IVPair] RETURNS [prev, same, next: MaybePair] ~ { s: Singleton ~ NARROW[fn.data]; prev _ same _ next _ noMaybePair; SELECT TRUE FROM pair.left=s.pair.left => same _ [TRUE, s.pair]; Succeeds[pair.left, s.pair.left] => prev _ [TRUE, s.pair]; Preceeds[pair.left, s.pair.left] => next _ [TRUE, s.pair]; ENDCASE => NULL; RETURN}; SingletonSize: PROC [fn: IntFn, left: Interval, right: Collection, limit: LNAT] RETURNS [LNAT] ~ {RETURN [1]}; SingletonGetBounds: PROC [fn: IntFn] RETURNS [Interval] ~ { s: Singleton ~ NARROW[fn.data]; RETURN [[s.pair.left, s.pair.left]]}; SingletonCurRange: PROC [fn: IntFn] RETURNS [ConstSet] ~ { s: Singleton ~ NARROW[fn.data]; RETURN Colls.CreateSingleton[s.pair.right, s.right]}; SingletonRightSpace: PROC [fn: IntFn] RETURNS [Space] ~ { s: Singleton ~ NARROW[fn.data]; RETURN [s.right]}; Lyst: TYPE ~ REF LystPrivate; LystPrivate: TYPE ~ RECORD [ right: Space, elts: LOP, size: LNAT _ 0, bounds: Interval _ [INT.LAST, INT.FIRST] ]; CreateFromList: PUBLIC PROC [vals: LOP, oneToOne: BOOL _ FALSE, right: Space _ refs, invable: BOOL _ FALSE] RETURNS [ConstIntFn] ~ { lcs: REF LystClasses _ NARROW[List.Assoc[key: lystClassesKey, aList: right.other]]; l: Lyst ~ NEW [LystPrivate _ [right, vals]]; first, ordered: BOOL _ TRUE; prev: INT; IF lcs=NIL THEN { lcs _ NEW [LystClasses]; FOR isOneToOne: BOOL IN BOOL DO FOR isDense: BOOL IN BOOL DO FOR ordered: BOOL IN BOOL DO lcs[isOneToOne][isDense][ordered] _ CreateClass[[ HasPair: LystHasPair, Apply: LystApply, InvApply: LystInvApply, Scan: LystScan, Size: LystSize, GetBounds: LystGetBounds, RightSpace: LystRightSpace, isOneToOne: isOneToOne, isDense: isDense, ordered: ordered, mutability: constant, domainFixed: TRUE]]; ENDLOOP ENDLOOP ENDLOOP; right.other _ List.PutAssoc[lystClassesKey, lcs, right.other]; }; FOR vals _ vals, vals.rest WHILE vals#NIL DO l.size _ l.size+1; l.bounds.min _ MIN[l.bounds.min, vals.first.left]; l.bounds.max _ MAX[l.bounds.max, vals.first.left]; IF first THEN first _ FALSE ELSE IF vals.first.left#prev.SUCC THEN ordered _ FALSE; prev _ vals.first.left; ENDLOOP; {fn: IntFn _ [lcs[oneToOne][l.bounds.Length=IE[l.size]][ordered], l]; IF invable THEN fn _ fn.CreatePartnership[DeRef[CreateHashReln[[refInts, right], [TRUE, oneToOne], [FALSE, TRUE]].AsIntFn]]; RETURN fn.AsConst[]; }}; LystClasses: TYPE ~ ARRAY --isOneToOne--BOOL OF ARRAY --isDense--BOOL OF ARRAY --ordered--BOOL OF IntFnClass; lystClassesKey: ATOM ~ $StdIntFunctionsImplLystClasses; LystHasPair: PROC [fn: IntFn, pair: IVPair] RETURNS [BOOL] ~ { l: Lyst ~ NARROW[fn.data]; right: Space ~ l.right; FOR elts: LOP _ l.elts, elts.rest WHILE elts#NIL DO IF elts.first.left=pair.left AND right.SpaceEqual[pair.right, elts.first.right] THEN RETURN [TRUE]; ENDLOOP; RETURN [FALSE]}; LystApply: PROC [fn: IntFn, i: INT] RETURNS [MaybeValue] ~ { l: Lyst ~ NARROW[fn.data]; FOR elts: LOP _ l.elts, elts.rest WHILE elts#NIL DO IF elts.first.left=i THEN RETURN [[TRUE, elts.first.right]]; ENDLOOP; RETURN [noMaybe]}; LystInvApply: PROC [fn: IntFn, v: Value] RETURNS [MaybeInt] ~ { l: Lyst ~ NARROW[fn.data]; right: Space ~ l.right; FOR elts: LOP _ l.elts, elts.rest WHILE elts#NIL DO IF right.SpaceEqual[v, elts.first.right] THEN RETURN [[TRUE, elts.first.left]]; ENDLOOP; RETURN [noInt]}; LystScan: PROC [fn: IntFn, Test: Tester, left: Interval, right: Collection, bkwd: BOOL] RETURNS [MaybePair] ~ { l: Lyst ~ NARROW[fn.data]; IF bkwd THEN RETURN DefaultScan[fn, Test, left, right, bkwd]; FOR elts: LOP _ l.elts, elts.rest WHILE elts#NIL DO IF left.Contains[elts.first.left] AND right.HasMember[elts.first.right] AND Test[elts.first] THEN RETURN [[TRUE, elts.first]]; ENDLOOP; RETURN [noMaybePair]}; LystSize: PROC [fn: IntFn, left: Interval, right: Collection, limit: LNAT] RETURNS [LNAT] ~ { l: Lyst ~ NARROW[fn.data]; RETURN [l.size]}; LystGetBounds: PROC [fn: IntFn] RETURNS [Interval] ~ { l: Lyst ~ NARROW[fn.data]; RETURN [l.bounds]}; LystRightSpace: PROC [fn: IntFn] RETURNS [Space] ~ { l: Lyst ~ NARROW[fn.data]; RETURN [l.right]}; Simple: TYPE ~ REF SimplePrivate; SimplePrivate: TYPE ~ RECORD [ right: Space, bounds: Interval, d: INT, vals: SimpleElts, freezeCount: INT _ 0]; SimpleElts: TYPE ~ REF SimpleEltsPrivate; SimpleEltsPrivate: TYPE ~ RECORD [ vals: SEQUENCE size: NATURAL OF Value ]; SimpleClasses: TYPE ~ ARRAY --isOneToOne--BOOL OF ARRAY --dense--BOOL OF ARRAY --domainFixed--BOOL OF ARRAY Mutability OF IntFnClass; simpleClasses: REF SimpleClasses ~ NEW [SimpleClasses]; CreateSimple: PUBLIC PROC [bounds: Interval _ [0, -1], val: Value _ noValue, oneToOne, dense, domainFixed, invable: BOOL _ FALSE, rightSpace: Space _ refs] RETURNS [Array] ~ { vals: SimpleElts ~ NEW [SimpleEltsPrivate[bounds.Length.EN]]; simple: Simple ~ NEW [SimplePrivate _ [rightSpace, bounds, bounds.min, vals]]; FOR i: NATURAL IN [0 .. vals.size) DO vals[i] _ val ENDLOOP; IF val=noValue THEN simple.bounds _ simple.bounds.ClipTop[simple.bounds.min]; {fn: IntFn _ [simpleClasses[oneToOne][dense][domainFixed][variable], simple]; IF invable THEN { otherHalf: IntFn ~ DeRef[CreateHashReln[[refInts, rightSpace], [TRUE, oneToOne], [FALSE, TRUE]].AsIntFn]; [] _ otherHalf.AddColl[fn]; fn _ fn.CreatePartnership[otherHalf]; }; RETURN [fn]}}; CreateSimpleCopy: PUBLIC PROC [array: Array, bounds: Interval _ [], oneToOne, dense, domainFixed: NewBOOL _ SAME, invable: BOOL _ FALSE, rightSpace: Space _ NIL] RETURNS [Array] ~ { realBounds: Interval ~ array.GetBounds.Intersect[bounds]; realSpace: Space ~ IF rightSpace#NIL THEN rightSpace ELSE array.RightSpace; vals: SimpleElts ~ NEW [SimpleEltsPrivate[realBounds.Length.EN]]; simple: Simple ~ NEW [SimplePrivate _ [realSpace, realBounds, realBounds.min, vals]]; newOneToOne: BOOL ~ oneToOne.UpdateBool[array.IsOneToOne]; FOR i: INT IN [realBounds.min .. realBounds.max] DO vals[i-simple.d] _ array.Apply[i].Val ENDLOOP; {fn: IntFn _ [ simpleClasses [newOneToOne] [dense.UpdateBool[array.DomainIsDense]] [domainFixed.UpdateBool[array.DomainIsFixed]] [variable], simple]; IF invable THEN fn _ fn.CreatePartnership[DeRef[CreateHashReln[[refInts, realSpace], [TRUE, newOneToOne], [FALSE, TRUE]].AsIntFn]]; RETURN [fn]}}; SimpleApply: PROC [fn: IntFn, i: INT] RETURNS [mv: MaybeValue] ~ { simple: Simple ~ NARROW[fn.data]; IF fn.MutabilityOf=constant AND simple.freezeCount=0 THEN Complain[fn, unfrozen]; IF NOT simple.bounds.Contains[i] THEN RETURN [noMaybe]; mv.val _ simple.vals[i-simple.d]; mv.found _ mv.val # noValue; RETURN}; SimpleScan: PROC [fn: IntFn, Test: Tester, left: Interval, right: Collection, bkwd: BOOL] RETURNS [MaybePair] ~ { simple: Simple ~ NARROW[fn.data]; vals: SimpleElts ~ simple.vals; scanBounds: Interval ~ simple.bounds.Intersect[left]; IF fn.MutabilityOf=constant AND simple.freezeCount=0 THEN Complain[fn, unfrozen]; IF bkwd THEN FOR i: INT DECREASING IN [scanBounds.min .. scanBounds.max] DO pair: IVPair ~ [i, simple.vals[i-simple.d]]; IF pair.right#noValue AND right.HasMember[pair.right] AND Test[pair] THEN RETURN [[TRUE, pair]]; ENDLOOP ELSE FOR i: INT IN [scanBounds.min .. scanBounds.max] DO pair: IVPair ~ [i, simple.vals[i-simple.d]]; IF pair.right#noValue AND right.HasMember[pair.right] AND Test[pair] THEN RETURN [[TRUE, pair]]; ENDLOOP; RETURN [noMaybePair]}; SimpleGetBounds: PROC [fn: IntFn] RETURNS [Interval] ~ { simple: Simple ~ NARROW[fn.data]; IF fn.MutabilityOf=constant AND simple.freezeCount=0 AND NOT fn.DomainIsFixed THEN Complain[fn, unfrozen]; RETURN [simple.bounds]}; SimpleCopy: PROC [fn: IntFn] RETURNS [VarIntFn] ~ { simple: Simple ~ NARROW[fn.data]; IF fn.MutabilityOf=constant AND simple.freezeCount=0 THEN Complain[fn, unfrozen]; RETURN CreateSimpleCopy[fn].AsVar}; SimpleFreeze: PROC [fn: IntFn] RETURNS [ConstIntFn] ~ { simple: Simple ~ NARROW[fn.data]; IF fn.MutabilityOf#variable THEN Complain[fn, notVariable]; simple.freezeCount _ simple.freezeCount + 1; RETURN AsConst[[ simpleClasses[fn.IsOneToOne][fn.DomainIsDense][fn.DomainIsFixed][constant], simple]]; }; SimpleThaw: PROC [fn: IntFn] ~ { simple: Simple ~ NARROW[fn.data]; IF fn.MutabilityOf#variable THEN Complain[fn, notVariable]; IF simple.freezeCount<=0 THEN Complain[fn, "too many thaws"]; simple.freezeCount _ simple.freezeCount-1; RETURN}; SimpleAddColl: PROC [fn, other: IntFn, if: IfNewsPair] RETURNS [some: NewsSetPair] ~ { simple: Simple ~ NARROW[fn.data]; right: Space ~ simple.right; bounds: Interval; d: INT; vals: SimpleElts; newCount: NATURAL _ 0; expansionCount: NATURAL _ 0; Per: PROC [pair: IVPair] RETURNS [pass: BOOL _ FALSE] ~ { news: News _ different; IF bounds.Contains[pair.left] THEN { old: Value ~ vals[pair.left-d]; IF old=noValue THEN { news _ new; newCount _ newCount+1; } ELSE IF right.SpaceEqual[pair.right, old] THEN news _ same } ELSE IF fn.DomainIsFixed THEN fn.Complain[fixedDomain] ELSE { de: NATURAL ~ EnsureContains[simple, [pair.left, pair.left]]; IF de=0 THEN ERROR; expansionCount _ expansionCount + de; newCount _ newCount+1; bounds _ simple.bounds; d _ simple.d; vals _ simple.vals; news _ new; }; vals[pair.left-d] _ pair.right; some[leftToRight][news] _ TRUE; RETURN}; IF fn.MutabilityOf # variable THEN fn.Complain[notVariable]; IF simple.freezeCount#0 THEN fn.Complain[frozen]; some _ ALL[ALL[FALSE]]; IF other.QualityOf[$GetBounds] >= goodDefault THEN expansionCount _ EnsureContains[simple, other.GetBounds[]]; bounds _ simple.bounds; d _ simple.d; vals _ simple.vals; [] _ other.Scan[Per]; IF newCount>expansionCount THEN ERROR; IF fn.DomainIsDense AND newCount= simple.bounds.min AND bounds.max <= simple.bounds.max THEN RETURN [0]; {oldVals: SimpleElts ~ simple.vals; oldSize: NATURAL ~ oldVals.size; oldBounds: Interval ~ simple.bounds; newBounds: Interval ~ 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}}}; SimpleDenseRemColl: PROC [fn, other: IntFn] RETURNS [hadSome, hadAll: BoolPair] ~ { simple: Simple ~ NARROW[fn.data]; vals: SimpleElts ~ simple.vals; right: Space ~ simple.right; oldBounds: Interval ~ simple.bounds; otherBounds: Interval ~ other.GetBounds[]; scanBounds: Interval ~ oldBounds.Intersect[otherBounds]; mustKeep: Interval _ anEmptyInterval; may: Interval _ oldBounds; losses: NATURAL _ 0; Per: PROC [pair: IVPair] RETURNS [pass: BOOL _ FALSE] ~ { i: INT ~ pair.left; hadIt: BOOL ~ right.SpaceEqual[pair.right, vals[i-simple.d]]; IF hadIt THEN { IF fn.DomainIsFixed THEN fn.Complain[fixedDomain] ELSE IF mustKeep.Contains[i] THEN fn.Complain["RemColl does not leave domain dense"] 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; hadSome[leftToRight] _ TRUE; losses _ losses + 1; } ELSE { IF NOT may.Contains[i] THEN fn.Complain["RemColl does not leave domain dense"] ELSE IF NOT mustKeep.Contains[i] THEN mustKeep _ [min: MIN[mustKeep.min, i], max: MAX[mustKeep.max, i]]; hadAll[leftToRight] _ FALSE; }; }; IF fn.MutabilityOf # variable THEN fn.Complain[notVariable]; IF simple.freezeCount#0 THEN fn.Complain[frozen]; hadSome _ ALL[FALSE]; hadAll _ ALL[scanBounds=otherBounds]; [] _ other.Scan[Per, scanBounds]; simple.bounds _ may; simple.d _ simple.d - oldBounds.min + simple.bounds.min; IF may.Length.AddI[losses] # oldBounds.Length THEN fn.Complain["RemColl does not leave domain dense"]; RETURN}; SimpleSparseRemColl: PROC [fn, other: IntFn] RETURNS [hadSome, hadAll: BoolPair] ~ { simple: Simple ~ NARROW[fn.data]; vals: SimpleElts ~ simple.vals; right: Space ~ simple.right; oldBounds: Interval ~ simple.bounds; otherBounds: Interval ~ other.ImproveBounds[[]]; scanBounds: Interval ~ otherBounds.Intersect[oldBounds]; rebound: BOOL _ FALSE; Per: PROC [pair: IVPair] RETURNS [pass: BOOL _ FALSE] ~ { i: INT ~ pair.left; hadIt: BOOL ~ right.SpaceEqual[pair.right, vals[i-simple.d]]; IF hadIt THEN { IF fn.DomainIsFixed THEN fn.Complain[fixedDomain]; IF i=oldBounds.min OR i=oldBounds.max THEN rebound _ TRUE; vals[i-simple.d] _ noValue; hadSome[leftToRight] _ TRUE; } ELSE { hadAll[leftToRight] _ FALSE; }; }; IF fn.MutabilityOf # variable THEN fn.Complain[notVariable]; IF simple.freezeCount#0 THEN fn.Complain[frozen]; hadSome _ ALL[FALSE]; hadAll _ ALL[scanBounds=otherBounds]; [] _ other.Scan[Per, oldBounds]; IF rebound THEN FixBounds[fn, simple]; RETURN}; FixBounds: PROC [fn: IntFn, simple: Simple] ~ { vals: SimpleElts ~ simple.vals; d: INT ~ simple.d; oldBounds: Interval ~ simple.bounds; newBounds: Interval _ 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: Interval] ~ { IF where.Empty OR simple.bounds.Empty OR where.max < simple.bounds.min OR where.min > simple.bounds.max THEN RETURN; FOR i: INT IN [MAX[where.min, simple.bounds.min] .. MIN[where.max, simple.bounds.max]] DO simple.vals[i-simple.d] _ noValue 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 [fn, with: IntFn, where, clip: Interval] RETURNS [losses, gains: EINT] ~ { simple: Simple ~ NARROW[fn.data]; clipLen: EINT ~ clip.Length; whereLen: EINT ~ where.Length; tailShift: EINT ~ clipLen.Sub[whereLen]; insertShift: EINT ~ ISub[where.min, clip.min]; oldBounds: Interval ~ simple.bounds; insertBoundsEst: Interval ~ clip.ClipShiftInterval[insertShift]; beforeTail: INT ~ IF where.Empty THEN where.min-1 ELSE where.max; newBoundsEst, headNeed, tailNeed: Interval; bounds: Interval _ anEmptyInterval; AddStuff: PROC [new: Interval] ~ { bounds _ bounds.MBI[new]; }; AddPair: PROC [pair: IVPair] RETURNS [pass: BOOL _ FALSE] ~ { i: INT ~ insertShift.AddI[pair.left].EI; [] _ EnsureContains[simple, [i, i]]; AddStuff[[i, i]]; simple.vals[i-simple.d] _ pair.right; TRUSTED {gains _ gains.Succ}; }; IF fn.MutabilityOf # variable THEN fn.Complain[notVariable]; IF simple.freezeCount#0 THEN fn.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]}; TRUSTED {losses _ oldBounds.Intersect[where].Length; gains _ zero}; [] _ EnsureContains[simple, tailNeed]; AddStuff[headNeed]; AddStuff[tailNeed]; IF NOT tailNeed.Empty THEN SELECT tailShift.Sgn[] FROM <0 => { FOR i: INT IN [tailNeed.min .. tailNeed.max] DO j: INT ~ IE[i].Sub[tailShift].EI; simple.vals[i-simple.d] _ simple.vals[j-simple.d]; ENDLOOP; {olds: Interval ~ oldBounds.ClipBot[MAX[tailNeed.max, where.max]]; FOR i: INT IN [olds.min .. olds.max] DO simple.vals[i-simple.d] _ noValue; ENDLOOP; }}; >0 => { FOR i: INT DECREASING IN [tailNeed.min .. tailNeed.max] DO j: INT ~ IE[i].Sub[tailShift].EI; simple.vals[i-simple.d] _ simple.vals[j-simple.d]; ENDLOOP; {olds: Interval ~ oldBounds.ClipBot[insertBoundsEst.max].ClipTop[tailNeed.min]; FOR i: INT IN [olds.min .. olds.max] DO simple.vals[i-simple.d] _ noValue; ENDLOOP; }}; =0 => NULL; ENDCASE => ERROR; LeftDelete[simple, insertBoundsEst]; [] _ with.Scan[AddPair, clip]; IF fn.DomainIsDense AND gains.Add[headNeed.Length].Add[tailNeed.Length] # bounds.Length THEN fn.Complain["ReplaceMe didn't keep domain dense"]; IF fn.DomainIsFixed AND bounds#oldBounds THEN fn.Complain[fixedDomain]; simple.bounds _ bounds; IF NOT (bounds.Empty OR oldBounds.Empty) THEN simple.d _ simple.d-oldBounds.min+simple.bounds.min; }; SimpleReshapeMe: PROC [fn: IntFn, lt: XForm, lb: Interval, rt: OneToOne, rb: Collection] ~ { simple: Simple ~ NARROW[fn.data]; IF fn.MutabilityOf#variable THEN fn.Complain[notVariable]; IF simple.freezeCount#0 THEN fn.Complain[frozen]; IF rb#passAll OR rt#PCs.id OR lt.d#1 THEN { vals: SimpleElts ~ simple.vals; d: INT ~ simple.d; oldBounds: Interval ~ simple.bounds; newBounds: Interval ~ lt.XFormInterval[oldBounds]; new: IntFn ~ CreateSimple[ bounds: newBounds, val: fn.First.DP.right, oneToOne: fn.IsOneToOne, domainFixed: fn.DomainIsFixed, dense: fn.DomainIsDense, rightSpace: simple.right]; simple2: Simple ~ NARROW[new.data]; vals2: SimpleElts ~ simple2.vals; d2: INT ~ simple2.d; i: INT _ oldBounds.min; j: INT _ lt.XFormInt[i]; IF fn.DomainIsFixed AND newBounds#simple.bounds THEN fn.Complain[fixedDomain]; IF lt.d=0 THEN fn.Complain["Given a degenerate XForm"]; IF fn.DomainIsDense AND lt.d#1 AND lt.d#-1 AND oldBounds.max>oldBounds.min THEN fn.Complain["ReshapeMe doesn't leave domain dense"]; FOR i _ i, i+1 WHILE i <= oldBounds.max DO vals2[j-d2] _ vals[i-d]; j _ j + lt.d; ENDLOOP; simple^ _ simple2^; } ELSE { unshifted: Interval ~ simple.bounds.Intersect[lb]; newBounds: Interval ~ unshifted.ClipShiftInterval[lt.o]; IF fn.DomainIsFixed AND newBounds#simple.bounds THEN fn.Complain[fixedDomain]; FOR i: INT IN [simple.bounds.min .. unshifted.min) DO simple.vals[i-simple.d] _ noValue ENDLOOP; FOR i: INT IN (unshifted.max .. simple.bounds.max] DO simple.vals[i-simple.d] _ noValue ENDLOOP; simple.d _ lt.XFormInt[simple.d]; simple.bounds _ newBounds; }; RETURN}; SimpleRightSpace: PROC [fn: IntFn] RETURNS [Space] ~ { simple: Simple ~ NARROW[fn.data]; RETURN [simple.right]}; Succeeds: PROC [a, b: INT] RETURNS [BOOL] ~ INLINE {RETURN [bINT.FIRST AND a=b-1]}; ClipPred: PROC [i: INT] RETURNS [INT] ~ INLINE {RETURN [IF i > INT.FIRST THEN i-1 ELSE INT.FIRST]}; ClipSucc: PROC [i: INT] RETURNS [INT] ~ INLINE {RETURN [IF i < INT.LAST THEN i+1 ELSE INT.LAST]}; Equal: PUBLIC PROC [a, b: IntFn, bounds: Interval _ []] RETURNS [BOOL] ~ { c: Basics.Comparison ~ Compare[a, b, bounds]; RETURN [c=equal]}; Hash: PUBLIC PROC [fn: IntFn, bounds: Interval _ []] RETURNS [hash: CARDINAL _ 0] ~ { right: Space ~ fn.RightSpace[]; PerPair: PROC [pair: IVPair] ~ { vh: CARDINAL _ right.SpaceHash[pair.right]; ih: CARDINAL _ HashIntI[pair.left]; this: CARD; IF ih=0 THEN ih _ 13; IF vh=0 THEN vh _ 17; this _ CARD[ih]*vh; hash _ hash + HashIntI[LOOPHOLE[this]]; RETURN}; IF right=NIL THEN Cant[fn]; fn.Enumerate[PerPair, bounds]; RETURN}; Compare: PUBLIC PROC [a, b: IntFn, bounds: Interval _ []] RETURNS [c: Basics.Comparison] ~ { right: Space ~ a.RightSpace[]; aBounds: Interval ~ a.ImproveBounds[bounds]; bBounds: Interval ~ b.ImproveBounds[bounds]; IF right=NIL THEN Cant[a]; bounds _ MBI[aBounds, bBounds]; FOR i: INT IN [bounds.min .. bounds.max] DO amv: MaybeValue ~ a.Apply[i]; bmv: MaybeValue ~ b.Apply[i]; IF amv.found#bmv.found THEN RETURN [IF bmv.found THEN less ELSE greater]; IF amv.found AND (c _ right.SpaceCompare[amv.val, bmv.val])#equal THEN RETURN; ENDLOOP; c _ equal}; RestrictionKey: ARRAY Restriction OF ATOM ~ [ unrestricted: $unrestricted, filtered: $filtered, restricted: $restricted, tiny: $tiny]; FromRestriction: PUBLIC PROC [r: Restriction] RETURNS [ATOM] ~ {RETURN [RestrictionKey[r]]}; GetRestriction: PUBLIC PROC [args: ArgList, i: NAT, default: Restriction _ unrestricted] RETURNS [Restriction] ~ { WHILE i>1 AND args#NIL DO args _ args.rest; i _ i-1 ENDLOOP; IF args=NIL THEN RETURN [default]; RETURN [SELECT args.first FROM $unrestricted => unrestricted, $filtered => filtered, $restricted => restricted, $tiny => tiny, ENDCASE => ERROR]; }; 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: [ Apply: SimpleApply, Scan: SimpleScan, GetBounds: SimpleGetBounds, Copy: SimpleCopy, Freeze: SimpleFreeze, Thaw: SimpleThaw, AddColl: SimpleAddColl, RemColl: IF dense THEN SimpleDenseRemColl ELSE SimpleSparseRemColl, ReplaceMe: SimpleReplaceMe, ReshapeMe: SimpleReshapeMe, RightSpace: SimpleRightSpace, isOneToOne: isOneToOne, isDense: dense, ordered: TRUE, mutability: mutability, domainFixed: domainFixed ], bkwdable: [TRUE, TRUE] ]; ENDLOOP ENDLOOP ENDLOOP ENDLOOP; }; Start[]; END. ψStdIntFunctions1.Mesa Last tweaked by Mike Spreitzer on October 16, 1987 10:22:09 am PDT 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. Κ!W˜code™KšœB™B—K˜KšΟk œD˜MK˜šΟnœœ˜Kšœ;˜BKšœ ˜K˜—K˜Kš œœžœžœžœ@˜wK˜˜&Kšžœ˜Kšžœ ˜Kšžœ˜Kšžœ ˜Kšžœ˜Kšžœ ˜Kšžœ ˜Kšžœ ˜Kšž œ˜Kšžœ˜&Kšžœ˜Kšœ œ˜Kšœ œ˜Kšœ œ˜Kšœ˜Kšœ œ˜Kšœœ˜ —K˜Kšœœ#œ˜6K˜šž œœœœ˜;Kšœœœ˜—K˜šž œœœœ ˜9Kšœœ ˜—K˜šž œœœ ˜˜>K˜—šœœœ˜,K˜Kšœœ ˜2Kšœœ ˜2Kšœœ œœœœœ œ˜SKšœ˜Kšœ˜—Kšœ,œ˜EKš œ œCœœœ ˜|Kšœ˜K˜—K˜Kšœ œœΟcœœœŸ œœœŸ œœ ˜mKšœœ#˜7K˜šž œœœœ˜>Kšœ œ ˜K˜š œœœœ˜3Kš œœ0œœœ˜cKšœ˜—Kšœœ˜—K˜šž œœœœ˜