DIRECTORY Basics USING [LongNumber, BITSHIFT, BITOR, BITAND], CD, Core, PipalCore, PipalInstanceTable; PipalInstanceTableImpl: CEDAR MONITOR IMPORTS Basics, PipalCore EXPORTS PipalInstanceTable = BEGIN OPEN PipalInstanceTable; freeInstanceValues: LIST OF InstanceValue _ NIL; Cons: PRIVATE PROC [iw: InstanceValue, list: LIST OF InstanceValue] RETURNS [new: LIST OF InstanceValue] = { IF freeInstanceValues=NIL THEN freeInstanceValues _ LIST [[[], NIL]]; -- too bad! IF freeInstanceValues.first#[[], NIL] THEN ERROR; -- something real bad going on! new _ freeInstanceValues; freeInstanceValues _ freeInstanceValues.rest; new.first _ iw; new.rest _ list; }; Dispose: PRIVATE PROC [list: LIST OF InstanceValue] RETURNS [rest: LIST OF InstanceValue] = { rest _ list.rest; list.first _ [[], NIL]; list.rest _ freeInstanceValues; freeInstanceValues _ list; IF freeInstanceValues.first#[[], NIL] THEN ERROR; -- something real bad going on! }; Halve: PROC [n: INT] RETURNS [INT] ~ INLINE { ln: Basics.LongNumber; ln.li _ n; ln.lo _ Basics.BITOR[Basics.BITSHIFT[ln.lo, -1], Basics.BITSHIFT[ln.hi, 15]]; ln.hi _ Basics.BITOR[Basics.BITSHIFT[ln.hi, -1], Basics.BITAND[ln.hi, 08000H]]; RETURN [ln.li]; }; Intersect: PROC [r1, r2: Rect] RETURNS [BOOL] = INLINE { RETURN [r1.x1<=r2.x2 AND r2.x1<=r1.x2 AND r1.y1<=r2.y2 AND r2.y1<=r1.y2] }; Inside: PROC [a, b: Rect] RETURNS [BOOL] = INLINE { RETURN[a.x1>=b.x1 AND a.x2<=b.x2 AND a.y1>=b.y1 AND a.y2<=b.y2] }; Intersection: PROC [r1, r2: Rect] RETURNS [Rect] = INLINE { RETURN [[x1: MAX[r1.x1, r2.x1], y1: MAX[r1.y1, r2.y1], x2: MIN[r1.x2, r2.x2], y2: MIN[r1.y2, r2.y2]]] }; NonEmpty: PROC [r: Rect] RETURNS [BOOL] = INLINE { RETURN [r.x1=bucket.y2-bucket.y1 THEN {mid: INT _ Halve[bucket.x1+bucket.x2]; bucket1.x2 _ mid; bucket2.x1 _ mid+1} ELSE {mid: INT _ Halve[bucket.y1+bucket.y2]; bucket1.y2 _ mid; bucket2.y1 _ mid+1}; }; HashRect: PROC [table: Table, rect: Rect] RETURNS [hash: NAT _ 1] = { bucket: Rect _ table.range; IF NOT Inside[rect, bucket] THEN ERROR; WHILE hash * 2 < table.data.size DO bucket1, bucket2: Rect; [bucket1, bucket2] _ Divide[bucket]; SELECT TRUE FROM Inside[rect, bucket1] => {hash _ hash * 2; bucket _ bucket1}; Inside[rect, bucket2] => {hash _ hash * 2 + 1; bucket _ bucket2}; ENDCASE => RETURN; ENDLOOP; }; HashInstance: PROC [table: Table, instance: Instance] RETURNS [hash: NAT] = INLINE { hash _ HashRect[table, InlineBBox[instance]]; }; Create: PUBLIC PROC [range: Rect, logSize: NAT _ 2] RETURNS [Table] = { data: REF TableData _ NEW [TableData[Basics.BITSHIFT[value: 1, count: logSize]]]; RETURN [NEW [TableRec _ [range: range, leafBuckets: 0, data: data]]]; }; ReHash: PROC [table: Table] = { oldData: REF TableData _ table.data; newData: REF TableData _ NEW [TableData[oldData.size*2]]; table.data _ newData; table.leafBuckets _ 0; FOR i: NAT IN [1 .. oldData.size) DO values: LIST OF InstanceValue _ oldData[i]; WHILE values#NIL DO hash: NAT _ HashInstance[table, values.first.instance]; IF newData[hash]=NIL THEN table.leafBuckets _ table.leafBuckets+1; newData[hash] _ Cons[values.first, newData[hash]]; values _ Dispose[values]; ENDLOOP; ENDLOOP; }; Insert: PUBLIC ENTRY PROC [table: Table, instance: Instance, value: Value] = { ENABLE UNWIND => NULL; hash: NAT _ HashInstance[table, instance]; IF table.data[hash]=NIL THEN table.leafBuckets _ table.leafBuckets+1; table.data[hash] _ Cons[[instance, value], table.data[hash]]; IF table.leafBuckets * 2 > table.data.size THEN ReHash[table]; }; Enumerate: PUBLIC PROC [table: Table, action: PROC [Instance, Value], rect: Rect _ universe] = { EnumerateBucket: PROC [hash: NAT] = { FOR ivs: LIST OF InstanceValue _ data[hash], ivs.rest WHILE ivs#NIL DO IF Intersect[InlineBBox[ivs.first.instance], clipped] THEN action[ivs.first.instance, ivs.first.value]; ENDLOOP; }; data: REF TableData _ table.data; -- stored in the local frame to avoid concurrent inconsistencies clipped: Rect _ Intersection[rect, table.range]; hash1, hash2, hash: NAT; IF NOT NonEmpty[clipped] THEN RETURN; -- empty rect hash1 _ hash2 _ hash _ HashRect[table, clipped]; WHILE hash>0 DO EnumerateBucket[hash]; hash _ hash/2 ENDLOOP; DO hash1 _ 2 * hash1; hash2 _ 2 * hash2 + 1; IF hash2>=data.size THEN RETURN; FOR hash IN [hash1 .. hash2] DO EnumerateBucket[hash] ENDLOOP; ENDLOOP; }; DeleteOutside: PUBLIC ENTRY PROC [table: Table, rect: Rect] = { FOR i: NAT IN [1 .. table.data.size) DO IF table.data[i]#NIL THEN { current: LIST OF InstanceValue _ table.data[i]; previous: LIST OF InstanceValue _ NIL; -- either NIL or the node before current allDeleted: BOOL _ TRUE; UNTIL current = NIL DO SELECT TRUE FROM Intersect[rect, InlineBBox[current.first.instance]] => { allDeleted _ FALSE; previous _ current; current _ current.rest; }; previous = NIL => current _ table.data[i] _ Dispose[current]; ENDCASE => current _ previous.rest _ Dispose[current]; ENDLOOP; IF allDeleted THEN table.leafBuckets _ table.leafBuckets-1; }; ENDLOOP; }; Size: PROC [table: Table] RETURNS [size: INT _ 0] = { Count: PROC [Instance, Value] = {size _ size + 1}; Enumerate[table, Count]; }; END. PipalInstanceTableImpl.mesa Copyright Σ 1987, 1988 by Xerox Corporation. All rights reversed. From Intervals, created by Bertrand Serlet, November 16, 1985 7:22:05 pm PST Bertrand Serlet, March 5, 1988 6:54:12 pm PST Jean-Marc Frailong January 16, 1988 5:30:56 pm PST Hand allocation for efficiency reasons equivalent to: new _ CONS [iw, list]; equivalent to: rest _ list.rest; only disposes of the first element! Because the compiler is brain-damaged and calls general division for INT/2 Returns r1 and r2 have some common points or border; [assumes r1, r2 normalized]. [TRUE if rects touch on a single point] Returns a inside of b (b inclusive border) Returns intersection of r1 and r2 Returns r is not empty [contains more points than the border] For debugging! Κ›– "cedar" style˜codešœ™KšœB™BKšœIΟk™LKšœ-™-Kšœ/™2K˜—š ˜ Kš œœœœœ˜3Kšœ˜ Kšœ˜K˜—šΟnœœ˜%Kšœ˜Kšœ˜Kšœœ˜K˜—šœœœœ˜0K™&K™—Kšœœ ™%šžœœœœœœœœ˜lKš œœœœœΟc ˜QKš œœœœŸ˜QKšœi˜iK˜K˜—Kšœ ™ Kšœ#™#šžœœœœœœœœ˜]Kšœ$œ>˜eKš œœœœŸ˜QK˜K˜—š žœœœœœœ˜-KšœEœ™JJšœ˜Jšœ ˜ Jšœœœœ ˜MJšœœœœ˜OKšœ ˜K˜K˜—š ž œœœœœ˜8JšœR™RJšœœ"™'Jšœœœœ˜HJšœ˜J˜—š žœœœœœ˜3Jšœ*™*Jšœ œ œ œ ˜?Jšœ˜J˜—šž œœœ œ˜;Jšœ!™!Jš œœœœœ˜eJšœ˜J˜—š žœœ œœœ˜2Jšœ=™=Jšœ œ ˜ Jšœ˜J˜—šž œœœœ˜EKšœ4˜4Kšœ$˜$K˜K˜—šžœœœœ˜GJšœ˜šœ*˜,JšœœD˜RJšœœE˜S—K˜K˜—šžœœœœ ˜EJšœ˜Jšœœœœ˜'šœ˜#Jšœ˜Jšœ$˜$šœœ˜Jšœ>˜>JšœA˜AJšœ œ˜—Jšœ˜—K˜K˜—š ž œœ$œœœ˜TJšœ-˜-K˜K˜—š žœœœœœ ˜GKšœœ œœ˜QKšœœ:˜EK˜K˜—šžœœ˜Kšœ œ˜$Kšœ œ œ˜9Kšœ˜Kšœ˜šœœœ˜$Kšœœœ˜+šœœ˜Kšœœ.˜7Kšœœœ)˜BKšœ2˜2Kšœ˜Kšœ˜—Kšœ˜—K˜K˜—šžœœœœ5˜NKšœœœ˜Kšœœ!˜*Kšœœœ)˜EKšœ=˜=Kšœ)œ˜>K˜K˜—šž œœœœ.˜`šžœœœ˜%š œœœ&œœ˜Fšœ4˜6Kšœ-˜1—Kšœ˜—K˜—KšœœŸ@˜bKšœ0˜0Kšœœ˜Kš œœœœŸ ˜3Kšœ0˜0Kšœœ&œ˜=š˜Kšœ)˜)Kšœœœ˜ Kšœœœœ˜>Kšœ˜—K˜K˜—šž œœœœ˜?šœœœ˜'šœœœ˜Kšœ œœ˜/Kšœ œœœŸ(˜OKšœ œœ˜šœ œ˜šœœ˜šœ8˜8Kšœ œ-˜?K˜—Kšœ œ/˜=Kšœ/˜6—Kšœ˜—Kšœ œ)˜;K˜—Kšœ˜—K˜K˜—Kšœ™šžœœœœ ˜5Kšžœœ'˜2Kšœ˜K˜K˜—šœ˜K˜K˜K˜——…—.Ο