DIRECTORY CDLRUCache, CD; CDLRUCacheImpl: CEDAR MONITOR LOCKS lruCache USING lruCache: LRUCache IMPORTS CD EXPORTS CDLRUCache = BEGIN AequivalenceProc: TYPE = PROC[mySpecific, other: REF ANY] RETURNS [BOOL]; NewProc: TYPE = PROC [] RETURNS [CD.ObPtr]; LRUCache: TYPE = REF LRUCacheRep; LRUCacheRep: PUBLIC TYPE = MONITORED RECORD [ freeObject: CD.ObPtr_NIL, freeEntry: CARDINAL_0, aequivalence: AequivalenceProc, new: NewProc, access: SEQUENCE size: CARDINAL OF LinkRecord -- access[0] is not used but a dummy ]; DefaultAequivalence: PROC [mySpecific, other: REF ANY] RETURNS [BOOL] = { RETURN [mySpecific=other] }; Create: PUBLIC PROC [size: CARDINAL, aequivalenceProc: AequivalenceProc, newProc: NewProc] RETURNS [LRUCache] = BEGIN lru: LRUCache; size _ MAX[MIN[size, 256], 1]+1; --users don't know that access[0] is a dummy lru _ NEW[LRUCacheRep[size]]; lru.aequivalence _ aequivalenceProc; IF lru.aequivalence=NIL THEN lru.aequivalence_DefaultAequivalence; lru.new _ newProc; RETURN [lru] END; UnusedOrNew: PUBLIC ENTRY PROC [lruCache: LRUCache] RETURNS [CD.ObPtr] = BEGIN ob: CD.ObPtr; IF lruCache.new=NIL THEN RETURN WITH ERROR CD.Error[ec: callingError, explanation: "no newproc defined"]; IF lruCache.freeObject=NIL THEN ob _ lruCache.new[] ELSE { ob _ lruCache.freeObject; lruCache.freeObject _ NIL }; RETURN [ob] END; LinkRecord: TYPE = RECORD[ object: CD.ObPtr, hash: INT, older, younger: INTEGER ]; hit: INT_0; missed: INT_0; Hit: PROC = INLINE {IF hit GOTO SomeError]] EXITS SomeError => RETURN [FALSE] END; RemoveEntry: INTERNAL PROC[entry: INTEGER] = BEGIN lruCache.access[lruCache.access[entry].older].younger _ lruCache.access[entry].younger; lruCache.access[lruCache.access[entry].younger].older _ lruCache.access[entry].older; END; IncludeEntryAsYoungest: INTERNAL PROC[entry: INTEGER] = BEGIN lruCache.access[entry].older _ lruCache.access[0].older; lruCache.access[entry].younger _ 0; lruCache.access[lruCache.access[0].older].younger _ entry; lruCache.access[0].older _ i; END; i: INTEGER; hash: INT = Hash[ob]; FOR i _ lruCache.access[0].older, lruCache.access[i].older WHILE i#0 DO IF hash=lruCache.access[i].hash AND Aequivalent[lruCache.access[i].object, ob] THEN { Hit[]; RemoveEntry[i]; IncludeEntryAsYoungest[i]; lruCache.freeObject _ ob; RETURN [lruCache.access[i].object] }; ENDLOOP; Missed[]; IF lruCache.freeEntry