001: package gnu.jemacs.buffer;
002:
003: import gnu.mapping.*;
004:
005: /**
006: * A buffer-local variable (Location).
007: */
008:
009: public class BufferLocal extends IndirectableLocation {
010: boolean all;
011:
012: final Symbol name;
013:
014: Buffer cachedBuffer;
015:
016: /** Index in <code>cachedBuffer</code>'s <code>localBindings</code> array. */
017: int cachedIndex;
018:
019: BufferLocal(Symbol name, boolean all) {
020: this .name = name;
021: this .all = all;
022: }
023:
024: public final Symbol getKeySymbol() {
025: return name;
026: }
027:
028: public static void make(Symbol symbol, boolean all) {
029: Environment env = Environment.getCurrent();
030: NamedLocation loc = env.getLocation(symbol, null, true);
031: Location base = loc.getBase();
032: if (base instanceof BufferLocal) {
033: if (all)
034: ((BufferLocal) base).all = true;
035: return;
036: }
037: BufferLocal bloc = new BufferLocal(symbol, all);
038: // Not sure if this is 100% correct. FIXME.
039: // We have to be careful to avoid cycles, handle INDIERCT_DEFINES, etc.
040: bloc.base = loc.getBaseForce();
041: bloc.setAlias(loc);
042: }
043:
044: public Object get(Object defaultValue) {
045: Buffer buffer = Buffer.getCurrent();
046: return buffer == null ? base.get(defaultValue) : get(buffer,
047: defaultValue);
048: }
049:
050: public Object get(Buffer buffer, Object defaultValue) {
051: Object[] localBindings = buffer.localBindings;
052: if (buffer == cachedBuffer) {
053: int i = cachedIndex;
054: if (i > 0)
055: return localBindings[i];
056: } else if (localBindings != null) {
057: Symbol n = this .getKeySymbol();
058: int len = localBindings.length;
059: cachedBuffer = buffer;
060: for (int i = 0; i < len; i += 2) {
061: if (localBindings[i] == n) {
062: cachedIndex = ++i;
063: return localBindings[i];
064: }
065: }
066: cachedIndex = 0;
067: }
068: return base != null ? base.get(defaultValue)
069: : value == Location.UNBOUND ? defaultValue : value;
070: }
071:
072: public boolean isBound() {
073: Buffer buffer = Buffer.getCurrent();
074: return buffer == null ? base.isBound() : isBound(buffer);
075: }
076:
077: public boolean isBound(Buffer buffer) {
078: Object[] localBindings = buffer.localBindings;
079: Object unb = Location.UNBOUND;
080: if (buffer == cachedBuffer) {
081: int i = cachedIndex;
082: if (i >= 0)
083: return localBindings[i] != unb;
084: } else if (localBindings != null) {
085: Symbol n = this .getKeySymbol();
086: int len = localBindings.length;
087: cachedBuffer = buffer;
088: for (int i = 0; i < len; i += 2) {
089: if (localBindings[i] == n) {
090: cachedIndex = ++i;
091: return localBindings[i] != unb;
092: }
093: }
094: cachedIndex = 0;
095: }
096: return super .isBound();
097: }
098:
099: public synchronized final void set(Object newValue) {
100: Buffer buffer = Buffer.getCurrent();
101: if (buffer == null)
102: base.set(newValue);
103: else
104: set(buffer, newValue);
105: }
106:
107: public synchronized final void set(Buffer buffer, Object newValue) {
108: Object[] localBindings = buffer.localBindings;
109: int avail = -1;
110: Symbol n = this .getKeySymbol();
111: if (buffer == cachedBuffer) {
112: int i = cachedIndex;
113: if (i >= 0) {
114: localBindings[i] = newValue;
115: return;
116: }
117: } else if (localBindings != null) {
118: int len = localBindings.length;
119: for (int i = 0; i < len; i += 2) {
120: Object key = localBindings[i];
121: if (key == n) {
122: cachedBuffer = buffer;
123: cachedIndex = ++i;
124: localBindings[i] = newValue;
125: return;
126: }
127: if (key == null)
128: avail = i;
129: }
130: cachedIndex = 0;
131: }
132: if (all) {
133: if (avail < 0) {
134: if (localBindings == null) {
135: localBindings = new Object[20];
136: buffer.localBindings = localBindings;
137: avail = 0;
138: } else {
139: avail = localBindings.length;
140: Object[] newBindings = new Object[2 * avail];
141: System.arraycopy(localBindings, 0, newBindings, 0,
142: avail);
143: buffer.localBindings = localBindings = newBindings;
144: }
145: }
146: localBindings[avail] = n;
147: cachedBuffer = buffer;
148: cachedIndex = ++avail;
149: localBindings[avail] = newValue;
150: } else if (base == null)
151: value = newValue;
152: else
153: base.set(newValue);
154: }
155: }
|