001: // Copyright (c) 1996-2000, 2001, 2002, 2004 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.mapping;
005:
006: import java.io.*;
007:
008: /** Concrete implementation of <code>Environment</code>.
009: * (Should consider merging this code with Table2D.)
010: */
011:
012: public class SimpleEnvironment extends Environment {
013: NamedLocation[] table;
014: int log2Size;
015: private int mask;
016: /** Doesn't count inherited bindings. */
017: int num_bindings;
018: int currentTimestamp;
019:
020: /** Size does not include inherited Locations. */
021: public int size() {
022: return num_bindings;
023: }
024:
025: public static Location getCurrentLocation(String name) {
026: return getCurrent().getLocation(name, true);
027: }
028:
029: public static Object lookup_global(Symbol name)
030: throws UnboundLocationException {
031: Location binding = getCurrent().lookup(name);
032: if (binding == null)
033: throw new UnboundLocationException(name);
034: return binding.get();
035: }
036:
037: /** A special "end-of-list" value added for the sake of getEnvironment. */
038: NamedLocation sharedTail;
039:
040: public SimpleEnvironment() {
041: this (64);
042: }
043:
044: public SimpleEnvironment(String name) {
045: this ();
046: setName(name);
047: }
048:
049: public SimpleEnvironment(int capacity) {
050: log2Size = 4;
051: while (capacity > (1 << log2Size))
052: log2Size++;
053: capacity = 1 << log2Size;
054: table = new NamedLocation[capacity];
055: mask = capacity - 1;
056:
057: sharedTail = new PlainLocation(null, null, this );
058: }
059:
060: public NamedLocation lookup(Symbol name, Object property, int hash) {
061: return lookupDirect(name, property, hash);
062: }
063:
064: public NamedLocation lookupDirect(Symbol name, Object property,
065: int hash) {
066: int index = hash & this .mask;
067: for (NamedLocation loc = table[index]; loc != null; loc = loc.next) {
068: if (loc.matches(name, property))
069: return loc;
070: }
071: return null;
072: }
073:
074: public synchronized NamedLocation getLocation(Symbol name,
075: Object property, int hash, boolean create) {
076: NamedLocation loc = lookup(name, property, hash);
077: if (loc != null)
078: return loc;
079: if (!create)
080: return null;
081: return addUnboundLocation(name, property, hash);
082: }
083:
084: protected NamedLocation addUnboundLocation(Symbol name,
085: Object property, int hash) {
086: int index = hash & mask;
087: NamedLocation loc = newEntry(name, property, index);
088: loc.base = null;
089: loc.value = Location.UNBOUND;
090: return loc;
091: }
092:
093: public void put(Symbol key, Object property, Object newValue) {
094: boolean create = (flags & CAN_IMPLICITLY_DEFINE) != 0;
095: Location loc = getLocation(key, property, create);
096: if (loc == null)
097: throw new UnboundLocationException(key);
098: else if (loc.isConstant())
099: throw new IllegalStateException(
100: "attempt to modify read-only location: " + key
101: + " in " + this + " loc:" + loc);
102: loc.set(newValue);
103: }
104:
105: // Rename to newEntry? FIXME
106: NamedLocation newLocation(Symbol name, Object property) {
107: if ((flags & THREAD_SAFE) != 0)
108: return new SharedLocation(name, property, currentTimestamp);
109: else
110: return new PlainLocation(name, property);
111: }
112:
113: NamedLocation newEntry(Symbol name, Object property, int index) {
114: NamedLocation loc = newLocation(name, property);
115: NamedLocation first = table[index];
116: loc.next = first == null ? sharedTail : first;
117: table[index] = loc;
118: num_bindings++;
119: if (num_bindings >= table.length)
120: rehash();
121: return loc;
122: }
123:
124: public NamedLocation define(Symbol sym, Object property, int hash,
125: Object newValue) {
126: int index = hash & mask;
127: NamedLocation first = table[index];
128: NamedLocation loc = first;
129: for (;;) {
130: if (loc == null) {
131: // FIXME increment numBindings?
132: loc = newEntry(sym, property, index);
133: loc.set(newValue);
134: return loc;
135: } else if (loc.matches(sym, property)) {
136: if (!(loc.isBound() ? getCanDefine() : getCanRedefine()))
137: redefineError(sym, property, loc);
138: loc.base = null;
139: loc.value = newValue;
140: return loc;
141: }
142: loc = loc.next;
143: }
144: }
145:
146: public void define(Symbol sym, Object property, Object newValue) {
147: int hash = sym.hashCode() ^ System.identityHashCode(property);
148: define(sym, property, hash, newValue);
149: }
150:
151: protected void redefineError(Symbol name, Object property,
152: Location loc) {
153: throw new IllegalStateException(
154: "prohibited define/redefine of " + name + " in " + this );
155: }
156:
157: public NamedLocation addLocation(Symbol name, Object property,
158: Location loc) {
159: return addLocation(name, property, name.hashCode()
160: ^ System.identityHashCode(property), loc);
161: }
162:
163: // FIXME rename to define
164: NamedLocation addLocation(Symbol name, Object property, int hash,
165: Location loc) {
166: if (loc instanceof ThreadLocation
167: && ((ThreadLocation) loc).property == property)
168: loc = ((ThreadLocation) loc).getLocation();
169: NamedLocation nloc = lookupDirect(name, property, hash);
170: if (loc == nloc)
171: return nloc;
172: boolean bound = (nloc != null);
173: if (!bound)
174: nloc = addUnboundLocation(name, property, hash);
175: if ((flags & CAN_DEFINE + CAN_REDEFINE) != CAN_DEFINE
176: + CAN_REDEFINE) {
177: if (bound)
178: bound = nloc.isBound();
179: // We do this redundant testing to avoid invoking isBound,
180: // which may be expensive and/or cause needless errors, such in the
181: // case of a lazy ClassMemberLocation referring to a missing class.
182: if (bound ? ((flags & CAN_REDEFINE) == 0)
183: : ((flags & CAN_DEFINE) == 0) && loc.isBound())
184: ;
185: redefineError(name, property, nloc);
186: }
187: if ((flags & Environment.INDIRECT_DEFINES) != 0)
188: nloc.base = ((SimpleEnvironment) ((InheritingEnvironment) this )
189: .getParent(0)).addLocation(name, property, hash,
190: loc);
191: else
192: nloc.base = loc;
193: nloc.value = IndirectableLocation.INDIRECT_FLUIDS;
194: return nloc;
195: }
196:
197: void rehash() {
198: NamedLocation[] oldTable = table;
199: int oldCapacity = oldTable.length;
200: int newCapacity = 2 * oldCapacity;
201: NamedLocation[] newTable = new NamedLocation[newCapacity];
202: int newMask = newCapacity - 1;
203: for (int i = oldCapacity; --i >= 0;) {
204: for (NamedLocation element = oldTable[i]; element != null
205: && element != sharedTail;) {
206: NamedLocation next = element.next;
207: Symbol name = element.name;
208: Object property = element.property;
209: int hash = name.hashCode()
210: ^ System.identityHashCode(property);
211: int j = hash & newMask;
212: NamedLocation head = newTable[j];
213: if (head == null)
214: head = sharedTail;
215: element.next = head;
216: newTable[j] = element;
217: element = next;
218: }
219: }
220: table = newTable;
221: log2Size++;
222: mask = newMask;
223: }
224:
225: public Location unlink(Symbol symbol, Object property, int hash) {
226: int index = hash & this .mask;
227: NamedLocation prev = null;
228: NamedLocation loc = table[index];
229: while (loc != null) {
230: NamedLocation next = loc.next;
231: if (loc.matches(symbol, property)) {
232: if (!getCanRedefine())
233: redefineError(symbol, property, loc);
234: if (prev == null)
235: table[index] = next;
236: else
237: prev.next = loc;
238: num_bindings--;
239: return loc;
240: }
241: prev = loc;
242: loc = next;
243: }
244: return null;
245: }
246:
247: /** Does not enumerate inherited Locations. */
248: public LocationEnumeration enumerateLocations() {
249: LocationEnumeration it = new LocationEnumeration(table,
250: 1 << log2Size);
251: it.env = this ;
252: return it;
253: }
254:
255: /** Does enumerate inherited Locations. */
256: public LocationEnumeration enumerateAllLocations() {
257: return enumerateLocations();
258: }
259:
260: protected boolean hasMoreElements(LocationEnumeration it) {
261: for (;;) {
262: if (it.curLoc == null) {
263: if (--it.index < 0)
264: return false;
265: it.curLoc = it.bindings[it.index];
266: if (it.curLoc == null)
267: continue;
268: }
269: if (it.curLoc.name == null)
270: it.curLoc = it.curLoc.next;
271: else
272: break;
273: }
274: return true;
275: }
276:
277: public void writeExternal(ObjectOutput out) throws IOException {
278: out.writeObject(getSymbol());
279: }
280:
281: public void readExternal(ObjectInput in) throws IOException,
282: ClassNotFoundException {
283: setSymbol(in.readObject());
284: }
285:
286: public Object readResolve() throws ObjectStreamException {
287: String name = getName();
288: Environment env = (Environment) envTable.get(name);
289: if (env != null)
290: return env;
291: envTable.put(name, this );
292: return this ;
293:
294: }
295:
296: /* #ifdef JAVA2 */
297: public java.util.Set entrySet() {
298: return new EnvironmentMappings(this );
299: }
300:
301: /* #endif */
302:
303: public String toStringVerbose() {
304: StringBuffer sbuf = new StringBuffer();
305: toStringBase(sbuf);
306: return "#<environment " + getName() + " num:" + num_bindings
307: + " ts:" + currentTimestamp + sbuf + '>';
308: }
309:
310: protected void toStringBase(StringBuffer sbuf) {
311: ;
312: }
313: }
314:
315: /* #ifdef JAVA2 */
316: class EnvironmentMappings extends java.util.AbstractSet /* <Location> */
317: {
318: SimpleEnvironment env;
319:
320: public EnvironmentMappings(SimpleEnvironment env) {
321: this .env = env;
322: }
323:
324: public int size() {
325: return env.size();
326: }
327:
328: public java.util.Iterator iterator() {
329: return new LocationEnumeration(env);
330: }
331: }
332: /* #endif */
|