<> <> <> DIRECTORY Basics, Checksum, ImagerCache, ImagerDev USING [CharMask], ImagerFont USING [XChar], Real, RefTab; ImagerCacheImpl: CEDAR MONITOR LOCKS x USING x: Ref IMPORTS Basics, Checksum, Real, RefTab EXPORTS ImagerCache ~ BEGIN CharMask: TYPE ~ ImagerDev.CharMask; XChar: TYPE ~ ImagerFont.XChar; Ref: TYPE ~ REF Rep; Rep: PUBLIC TYPE ~ MONITORED RECORD [ size: NAT, limit: NAT, lgMaxSize: NAT, seq: SEQUENCE maxSize: CARDINAL OF CharMask ]; maxLoad: REAL _ 0.9; 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; new.limit _ MIN[Real.Round[maxSize*maxLoad], maxSize-1]; }; Size: PUBLIC ENTRY PROC [x: Ref] RETURNS [NAT] ~ { RETURN [x.size]; }; CharAndFont: TYPE ~ MACHINE DEPENDENT RECORD [char: XChar, font: REF]; Fetch: PUBLIC ENTRY PROC [x: Ref, font: REF, char: XChar] RETURNS [c: CharMask] ~ TRUSTED { last: CARDINAL ~ x.maxSize-1; cf: CharAndFont _ [char, font]; hash: CARDINAL _ Checksum.ComputeChecksum[nWords: SIZE[CharAndFont], p: @cf]; hash _ Basics.BITAND[last, Basics.BITXOR[hash, Basics.BITSHIFT[hash, -x.lgMaxSize]]]; UNTIL (c _ x[hash])=NIL OR (c.font=font AND c.char=char) DO <> IF hash = 0 THEN hash _ hash-1 ELSE hash _ last; ENDLOOP; }; Store: PUBLIC ENTRY PROC [x: Ref, charMask: CharMask] RETURNS [ok: BOOL] ~ TRUSTED { last: CARDINAL ~ x.maxSize-1; cf: CharAndFont _ [charMask.char, charMask.font]; hash: CARDINAL _ Checksum.ComputeChecksum[nWords: SIZE[CharAndFont], p: @cf]; c: CharMask; hash _ Basics.BITAND[last, Basics.BITXOR[hash, Basics.BITSHIFT[hash, -x.lgMaxSize]]]; UNTIL (c _ x[hash])=NIL OR (c.font=cf.font AND c.char=cf.char) DO <> IF hash = 0 THEN hash _ hash-1 ELSE hash _ last; ENDLOOP; IF c = NIL AND x.size >= x.limit THEN RETURN [ok: FALSE]; IF c = NIL THEN x.size _ x.size + 1; x[hash] _ charMask; RETURN [ok: TRUE]; }; 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 THEN { r _ Create[createSize]; IF NOT RefTab.Insert[cacheTab, atom, r] THEN { <> r _ NARROW[RefTab.Fetch[cacheTab, atom].val]; }; }; }; cacheTab: RefTab.Ref ~ RefTab.Create[]; END.