<> <> <> <> DIRECTORY Basics USING [BITAND, BITSHIFT, BITXOR], Checksum USING [ComputeChecksum], ImagerCache USING [], ImagerDevice USING [CharMask], ImagerFont USING [XChar], RefTab USING [Create, Fetch, Pairs, Ref, Store]; ImagerCacheImpl: CEDAR MONITOR LOCKS x USING x: Ref IMPORTS Basics, Checksum, RefTab EXPORTS ImagerCache ~ BEGIN CharMask: TYPE ~ ImagerDevice.CharMask; XChar: TYPE ~ ImagerFont.XChar; Ref: TYPE ~ REF Rep; Rep: PUBLIC TYPE ~ MONITORED RECORD [ size: NAT, lgMaxSize: NAT, stuffCount: LONG CARDINAL _ 0, seq: SEQUENCE maxSize: CARDINAL OF CharMask ]; Create: PUBLIC PROC [size: NAT] RETURNS [new: Ref] ~ { maxSize: CARDINAL _ 1; lgMaxSize: NAT _ 0; UNTIL maxSize > size DO maxSize _ 2*maxSize; lgMaxSize _ lgMaxSize + 1; ENDLOOP; new _ NEW[Rep[maxSize]]; new.size _ 0; new.lgMaxSize _ lgMaxSize; }; Size: PUBLIC ENTRY PROC [x: Ref] RETURNS [NAT] ~ { RETURN [x.size]; }; CharAndFont: TYPE ~ MACHINE DEPENDENT RECORD [char: XChar, font: REF]; maxProbes: NAT _ 15; Fetch: PUBLIC ENTRY PROC [x: Ref, font: REF, char: XChar] RETURNS [CharMask] ~ TRUSTED { last: CARDINAL ~ x.maxSize-1; cf: CharAndFont _ [char, font]; cksum: CARDINAL ~ Checksum.ComputeChecksum[nWords: SIZE[CharAndFont], p: @cf]; hash: CARDINAL _ Basics.BITAND[last, Basics.BITXOR[cksum, Basics.BITSHIFT[cksum, -x.lgMaxSize]]]; probes: CARDINAL _ 0; c: CharMask _ NIL; UNTIL (c _ x[hash])=NIL OR (c.font=font AND c.char=char) DO probes _ probes + 1; IF probes < maxProbes THEN { IF hash#0 THEN hash _ hash-1 ELSE hash _ last; } ELSE RETURN [NIL]; ENDLOOP; RETURN [c]; }; Store: PUBLIC ENTRY PROC [x: Ref, charMask: CharMask] RETURNS [ok: BOOL] ~ TRUSTED { last: CARDINAL ~ x.maxSize-1; cf: CharAndFont _ [charMask.char, charMask.font]; cksum: CARDINAL ~ Checksum.ComputeChecksum[nWords: SIZE[CharAndFont], p: @cf]; hash: CARDINAL _ Basics.BITAND[last, Basics.BITXOR[cksum, Basics.BITSHIFT[cksum, -x.lgMaxSize]]]; probes: CARDINAL _ 0; c: CharMask _ NIL; UNTIL (c _ x[hash])=NIL OR (c.font=cf.font AND c.char=cf.char) DO probes _ probes + 1; IF probes < maxProbes THEN { IF hash#0 THEN hash _ hash-1 ELSE hash _ last; } ELSE { <> x[hash] _ charMask; x.stuffCount _ x.stuffCount + 1; }; ENDLOOP; IF c = NIL AND x.size < x.maxSize THEN { x.size _ x.size + 1; c _ x[hash] _ charMask; }; RETURN [c # NIL]; }; Flush: PUBLIC ENTRY PROC [x: Ref] ~ { FOR i: INT IN [0..x.maxSize) DO x[i] _ NIL; ENDLOOP; x.size _ 0; }; GetList: PUBLIC ENTRY PROC [x: Ref] RETURNS [list: LIST OF CharMask _ NIL] ~ { FOR i: INT IN [0..x.maxSize) DO c: CharMask _ x[i]; IF c#NIL THEN list _ CONS[c, list]; ENDLOOP; }; GetNamedCache: PUBLIC PROC [atom: ATOM, createSize: NAT] RETURNS [r: Ref] ~ { r _ NARROW[RefTab.Fetch[cacheTab, atom].val]; IF r = NIL OR r.maxSize < createSize THEN { IF r # NIL THEN Flush[r]; r _ Create[createSize]; [] _ RefTab.Store[cacheTab, atom, r]; }; }; cacheTab: RefTab.Ref ~ RefTab.Create[]; FlushAll: PROC [newProbeLimit: NAT _ 15] ~ { epa: PROC [key, val: REF] RETURNS [quit: BOOL _ FALSE] ~ {Flush[NARROW[val]]}; [] _ RefTab.Pairs[cacheTab, epa]; maxProbes _ newProbeLimit; }; END.