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(/*@non_null*/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 }