001 /* Copyright 2000, 2001, Compaq Computer Corporation */ 002 003 package javafe.reader; 004 005 import java.util.Hashtable; 006 007 import javafe.ast.CompilationUnit; 008 import javafe.genericfile.*; 009 010 /** 011 * CachedReader takes a uncached Reader and produces a cached version 012 * of it using a simple implementation of caching via a HashTable. 013 * 014 * <p> Reads from GenericFiles with null canonicalIDs are not cached. 015 */ 016 017 public class CachedReader extends Reader 018 { 019 /*************************************************** 020 * * 021 * Creation: * 022 * * 023 **************************************************/ 024 025 /** 026 * The underlying Reader whose results we are caching. 027 */ 028 //@ invariant underlyingReader != null; 029 protected Reader underlyingReader; 030 031 /** 032 * Creating a cached version of a Reader: 033 */ 034 //@ requires reader != null; 035 public CachedReader(Reader reader) { 036 underlyingReader = reader; 037 038 //+@ set cache.keyType = \type(String); 039 //+@ set cache.elementType = \type(Object); 040 } 041 042 043 /*************************************************** 044 * * 045 * The Cache itself: * 046 * * 047 **************************************************/ 048 049 /** 050 * Our cache; maps the non-null canonicalID (if it has one) of a 051 * GenericFile (see GenericFile.getCanonicalID) to either a 052 * CompilationUnit or a CachedReader_Null. 053 */ 054 //@ invariant cache != null; 055 //+@ invariant cache.keyType == \type(String); 056 //+@ invariant cache.elementType == \type(Object); 057 protected Hashtable cache = new Hashtable(); 058 059 060 /*************************************************** 061 * * 062 * Caching methods: * 063 * * 064 **************************************************/ 065 066 /** 067 * Lookup a non-null GenericFile in the cache. 068 */ 069 //@ requires target != null; 070 final protected Object get(GenericFile target) { 071 String canonicalID = target.getCanonicalID(); 072 if (canonicalID==null) 073 return null; 074 075 return cache.get(canonicalID); 076 } 077 078 079 /** 080 * Store information about a non-null GenericFile in the cache; 081 * this has no effect if the GenericFile has a null canonicalID. 082 */ 083 //@ requires target != null; 084 final protected void put(GenericFile target, CompilationUnit value) { 085 String canonicalID = target.getCanonicalID(); 086 if (canonicalID==null) 087 return; 088 089 if (value != null) 090 cache.put(canonicalID, value); 091 else 092 cache.put(canonicalID, new CachedReader_Null()); 093 } 094 095 096 /** 097 * Is the result of read on target cached for this Reader?<p> 098 * 099 * Target must be non-null.<p> 100 */ 101 //@ requires target != null; 102 public boolean isCached(GenericFile target) { 103 String canonicalID = target.getCanonicalID(); 104 if (canonicalID==null) 105 return false; 106 107 return cache.containsKey(canonicalID); 108 } 109 110 /** 111 * Flush the saved info (if any) for target for this Reader. 112 * 113 * Target must be non-null.<p> 114 */ 115 //@ requires target != null; 116 public void flushTarget(GenericFile target) { 117 String canonicalID = target.getCanonicalID(); 118 if (canonicalID==null) 119 return; 120 121 cache.remove(canonicalID); 122 } 123 124 /** 125 * Flush all cached information for this Reader. 126 */ 127 public void flushAll() { 128 cache = new Hashtable(); 129 130 //+@ set cache.keyType = \type(String); 131 //+@ set cache.elementType = \type(Object); 132 } 133 134 135 /*************************************************** 136 * * 137 * Reading: * 138 * * 139 **************************************************/ 140 141 /** 142 * Attempt to read and parse a CompilationUnit from target. 143 * Any errors encountered are reported via javafe.util.ErrorSet. 144 * Null is returned iff an error was encountered.<p> 145 * 146 * 147 * By default, we attempt to read only a spec (e.g., specOnly is set 148 * in the resulting CompilationUnit) to save time. If avoidSpec is 149 * true, we attempt to return a non-spec, although this may not 150 * always be possible.<p> 151 * 152 * 153 * The results of this function (including null results, but not 154 * the action of reporting error messages) are cached. 155 * Only the value of avoidSpec used the first time a given file is 156 * read is used. This may result in a spec being returned 157 * unnecessarily when avoidSpec is true.<p> 158 * 159 * Target must be non-null.<p> 160 */ 161 public CompilationUnit read(GenericFile target, boolean avoidSpec) { 162 Object result = get(target); 163 if (result != null) { 164 if (result instanceof CompilationUnit) 165 return (CompilationUnit)result; 166 else if (result instanceof CachedReader_Null) 167 return null; 168 else 169 javafe.util.Assert.fail("impossible"); 170 } 171 172 CompilationUnit newResult = underlyingReader.read(target, avoidSpec); 173 put(target, newResult); 174 return newResult; 175 } 176 } 177 178 179 /** 180 * Instances of this class are used privately by CachedReader to 181 * represent null values in Hashtables. 182 */ 183 /*package*/ class CachedReader_Null { 184 }