<> <> <> <> <> <> DIRECTORY Basics USING [LongDivMod, LongMult], MB USING [Handle], MBVM USING [Base], PrincOps USING [wordsPerPage]; MBCache: CEDAR PROGRAM IMPORTS Basics EXPORTS MB, MBVM = BEGIN wordsPerPage: NAT = PrincOps.wordsPerPage; increment: NAT = wordsPerPage/SIZE[CachedPage]; cache: Cache; Cache: TYPE = REF CacheObject; CacheObject: TYPE = RECORD [ nPages: NAT, pages: SEQUENCE length: NAT OF CachedPage ]; CachedPage: TYPE = RECORD [ lp: REF PageOfWords, page: CARDINAL ]; PageOfWords: TYPE = ARRAY[0..wordsPerPage) OF WORD; data: MB.Handle _ NIL; lastTouched: CachedPage; InitCache: PUBLIC PROC [h: MB.Handle] = { data _ h; cache _ NEW[CacheObject[increment]]; cache.pages[0] _ [page: 0, lp: InitPage[]]; cache.pages[1] _ [page: LAST[CARDINAL], lp: NIL]; cache.nPages _ 2; lastTouched _ [page: LAST[CARDINAL], lp: NIL]; }; FinishCache: PUBLIC PROC = { cache _ NIL; data _ NIL; }; GetPage: PUBLIC PROC [page: MBVM.Base] RETURNS [LONG POINTER] = { low: NAT _ 0; high: NAT _ cache.nPages - 1; IF page = lastTouched.page THEN RETURN[LOOPHOLE[lastTouched.lp]]; DO probe: NAT = (low+high)/2; SELECT cache.pages[probe].page FROM < page => IF probe = low THEN EXIT ELSE low _ probe; > page => IF probe = high THEN EXIT ELSE high _ probe; ENDCASE => RETURN[LOOPHOLE[(lastTouched _ cache[probe]).lp]]; ENDLOOP; IF cache.nPages = cache.length THEN ExpandArray[]; FOR k: NAT DECREASING IN [low+1..cache.nPages) DO cache[k+1] _ cache[k]; ENDLOOP; lastTouched _ cache[low+1] _ [lp: InitPage[], page: page]; cache.nPages _ cache.nPages.SUCC; RETURN[LOOPHOLE[lastTouched.lp]] }; ExpandArray: PROC = { newLength: NAT = cache.length + increment; newCache: Cache = NEW[CacheObject[newLength]]; newCache.nPages _ cache.nPages; FOR i: NAT IN [0..cache.nPages) DO newCache.pages[i] _ cache.pages[i]; ENDLOOP; cache _ newCache; }; InitPage: PROC RETURNS [lp: REF PageOfWords] = { lp _ NEW[PageOfWords]; FOR i: CARDINAL IN [0..wordsPerPage) DO lp[i] _ 0; ENDLOOP; }; <<>> <> <<>> Read: PUBLIC PROC [p: POINTER] RETURNS [UNSPECIFIED] = { RETURN[LongRead[Basics.LongMult[data.mdsBase, wordsPerPage] + LOOPHOLE[p, CARDINAL]]] }; Write: PUBLIC PROC [p: POINTER, v: UNSPECIFIED] = { LongWrite[Basics.LongMult[data.mdsBase, wordsPerPage] + LOOPHOLE[p, CARDINAL], v]; }; CopyRead: PUBLIC PROC [from, to: POINTER, nwords: CARDINAL] = TRUSTED { FOR i: CARDINAL IN [0..nwords) DO (to+i)^ _ Read[from+i]; ENDLOOP; }; CopyWrite: PUBLIC PROC [from, to: POINTER, nwords: CARDINAL] = TRUSTED { FOR i: CARDINAL IN [0..nwords) DO Write[to+i, (from+i)^]; ENDLOOP; }; LongRead: PUBLIC PROC [p: LONG UNSPECIFIED] RETURNS [UNSPECIFIED] = TRUSTED { memPage: MBVM.Base; offset: CARDINAL; [quotient: memPage, remainder: offset] _ Basics.LongDivMod[LOOPHOLE[p], wordsPerPage]; RETURN[(GetPage[memPage]+offset)^] }; LongWrite: PUBLIC PROC [p: LONG UNSPECIFIED, v: UNSPECIFIED] = TRUSTED { memPage: MBVM.Base; offset: CARDINAL; [quotient: memPage, remainder: offset] _ Basics.LongDivMod[LOOPHOLE[p], wordsPerPage]; (GetPage[memPage]+offset)^ _ v; }; LongCopyRead: PUBLIC PROC [ from: LONG POINTER, to: LONG POINTER, nwords: CARDINAL] = TRUSTED { FOR i: CARDINAL IN [0..nwords) DO (to+i)^ _ LongRead[from+i]; ENDLOOP; }; LongCopyWrite: PUBLIC PROC [ from: LONG POINTER, to: LONG POINTER, nwords: CARDINAL] = TRUSTED { FOR i: CARDINAL IN [0..nwords) DO LongWrite[to+i, (from+i)^]; ENDLOOP; }; END.