<<>> <> <> <> <> <<>> DIRECTORY Basics32, CardTab, IO, Rope, Xl, XlPrivateResources; XlPrivateResourcesImpl: CEDAR MONITOR LOCKS c USING c: Connection IMPORTS Basics32, CardTab, Xl EXPORTS Xl, XlPrivateResources ~ BEGIN OPEN Xl, XlPrivateResources; ResourceStuffRep: PUBLIC TYPE = ResourceStuffRec; ResourceStuffRec: TYPE = RECORD [ base: CARD32, mask: CARD32, increment: CARD32, alloc: CARD32 ¬ 0, freeList: REF PieceRec ¬ NIL, attachments: CardTab.Ref ¬ NIL ]; pieceCount: NAT = 64; PieceRec: TYPE = RECORD [--invariant: only first PieceRec of free list may have used=0 a: ARRAY [0..pieceCount) OF ID ¬ ALL[0], used: NAT ¬ 0, next: REF PieceRec ¬ NIL ]; InitPrivateResources: PUBLIC PROC [c: Connection, resourceIdBase, resourceIdMask: CARD32] = { resources: REF ResourceStuffRec ¬ NEW[ResourceStuffRec ¬ [ base: resourceIdBase, mask: resourceIdMask, increment: Basics32.BITAND[resourceIdMask, CARD32.LAST-(resourceIdMask-1)], alloc: 0, attachments: CardTab.Create[] ]]; c.resourceStuff ¬ resources; }; <<>> MarkDead: PUBLIC PROC [c: Connection] = { resources: REF ResourceStuffRec ~ c.resourceStuff; IF resources#NIL THEN { resources.freeList ¬ NIL; IF resources.attachments#NIL THEN CardTab.Erase[resources.attachments] }; }; <<>> NewResourceID: PUBLIC --INTERNAL-- PROC [c: Connection] RETURNS [id: ID] = { MakeResourceID: PROC [resources: REF ResourceStuffRec] RETURNS [ID] = INLINE { IF resources.alloc = resources.mask THEN ERROR; -- out of ids; it is ok to wedge the connection resources.alloc ¬ resources.alloc + resources.increment; RETURN [Basics32.BITOR[resources.alloc, resources.base]]; }; resources: REF ResourceStuffRec ~ c.resourceStuff; free: REF PieceRec ¬ resources.freeList; IF free#NIL AND free.used=0 THEN free ¬ free.next; IF free#NIL AND free.used>0 THEN {free.used ¬ free.used-1; RETURN [free.a[free.used]]}; RETURN [MakeResourceID[resources]]; }; <<>> InternalFreeResourceID: PUBLIC --INTERNAL-- PROC [c: Connection, id: ID] = { IF Xl.Alive[c] AND ValidID[c, id] THEN { resources: REF ResourceStuffRec ~ c.resourceStuff; free: REF PieceRec ¬ resources.freeList; IF free=NIL OR free.used>=pieceCount THEN { free ¬ NEW[PieceRec ¬ [next: resources.freeList]]; resources.freeList ¬ free }; free.a[free.used] ¬ id; free.used ¬ free.used+1; }; }; EntryFreeResourceID: PUBLIC ENTRY PROC [c: Connection, id: ID] = { InternalFreeResourceID[c, id]; }; ValidID: PUBLIC PROC [c: Connection, id: ID] RETURNS [BOOL] = { resources: REF ResourceStuffRec ~ c.resourceStuff; RETURN [(id#0) AND (Basics32.BITAND[(CARD32.LAST-resources.mask), id-resources.base]=0)]; }; Attach: PUBLIC PROC [c: Connection, id: ID, ref: REF] = { <> <> resources: REF ResourceStuffRec ~ c.resourceStuff; [] ¬ CardTab.Store[resources.attachments, id, ref]; }; <<>> Detach: PUBLIC PROC [c: Connection, id: ID] = { <> resources: REF ResourceStuffRec ~ c.resourceStuff; [] ¬ CardTab.Delete[resources.attachments, id]; }; <<>> Fetch: PUBLIC PROC [c: Connection, id: ID] RETURNS [ref: REF] = { <> resources: REF ResourceStuffRec ~ c.resourceStuff; ref ¬ CardTab.Fetch[resources.attachments, id].val; }; END.