001: // Copyright (c) 2001, 2002, 2003 Per M.A. Bothner and Brainfood Inc.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003: package gnu.lists;
004:
005: import java.util.NoSuchElementException;
006:
007: /**
008: * A position in a sequence (list).
009: *
010: * Conceptually similar to Java2's ListIterator, but we use the name "Position"
011: * to indicate that it can be used to both indicate a position in a sequence
012: * and to iterate through a sequence. If you use a SeqPosition as a
013: * "position", you would not modify if (though it is possible the offset
014: * of the position in the sequence may change due to other update operations
015: * on the sequence). If you use a SeqPosition as an "iterator", you would
016: * initialize it to some beginnning position, and then modify the current
017: * position of the SeqPosition so it refers to successive elements.
018: *
019: * See the <a href="package-summary.html#iteration">package overview</a>
020: * for more information.
021: */
022:
023: public class SeqPosition implements
024: /* #ifdef JAVA2 */
025: java.util.ListIterator,
026: /* #endif */
027: java.util.Enumeration {
028: /**
029: * The Sequence relative to which ipos and xpos have meaning.
030: * This is normally the same as the Sequence we iterate through.
031: * However, if this is a TreePosition, it may an ancestor instead.
032: */
033: public AbstractSequence sequence;
034:
035: /**
036: * An integer that (together with xpos) indicates the current position.
037: * The actual value has no meaning, except as interpreted by sequence.
038: */
039: public int ipos;
040:
041: public SeqPosition() {
042: }
043:
044: public SeqPosition(AbstractSequence seq) {
045: this .sequence = seq;
046: }
047:
048: public SeqPosition(AbstractSequence seq, int offset, boolean isAfter) {
049: this .sequence = seq;
050: ipos = seq.createPos(offset, isAfter);
051: }
052:
053: public SeqPosition(AbstractSequence seq, int ipos) {
054: this .sequence = seq;
055: this .ipos = ipos;
056: }
057:
058: /** Creates a new SeqPosition, from a position pair.
059: * The position pair is copied (using copyPos).
060: */
061: public static SeqPosition make(AbstractSequence seq, int ipos) {
062: return new SeqPosition(seq, seq.copyPos(ipos));
063: }
064:
065: public SeqPosition copy() {
066: return new SeqPosition(sequence, sequence.copyPos(getPos()));
067: }
068:
069: public final void gotoStart(AbstractSequence seq) {
070: setPos(seq, seq.startPos());
071: }
072:
073: public final void gotoEnd(AbstractSequence seq) {
074: setPos(seq, seq.endPos());
075: }
076:
077: /** Set position before first child (of the element following position).
078: * @return true if there is a child sequence (which might be empty);
079: * false if current position is end of sequence or following element
080: * is atomic (cannot have children).
081: */
082: public boolean gotoChildrenStart() {
083: int child = sequence.firstChildPos(getPos());
084: if (child == 0)
085: return false;
086: ipos = child;
087: return true;
088: }
089:
090: /** True if there is an element following the current position.
091: * False if we are at the end. See java.util.Enumeration. */
092: public final boolean hasMoreElements() {
093: return hasNext();
094: }
095:
096: /** See java.util.Iterator. */
097: public boolean hasNext() {
098: return sequence.hasNext(getPos());
099: }
100:
101: /** Return a code (defined in Sequence) for the type of the next element. */
102: public int getNextKind() {
103: return sequence.getNextKind(getPos());
104: }
105:
106: /** Get the "tag name" for the next element, if any. */
107: public String getNextTypeName() {
108: return sequence.getNextTypeName(getPos());
109: }
110:
111: /** Get the "tag object" for the next element, if any. */
112: public Object getNextTypeObject() {
113: return sequence.getNextTypeObject(getPos());
114: }
115:
116: /** See java.util.Iterator. */
117: public boolean hasPrevious() {
118: return sequence.hasPrevious(getPos());
119: }
120:
121: /** See java.util.ListIterator. */
122: public Object next() {
123: Object result = getNext();
124: if (result == Sequence.eofValue || !gotoNext())
125: throw new NoSuchElementException();
126: return result;
127: }
128:
129: /** Move one element forwards, if possible.
130: * @return if we succeeded in moving forwards (i.e. not at end of sequence).
131: */
132: public boolean gotoNext() {
133: int next = sequence.nextPos(ipos);
134: if (next != 0) {
135: ipos = next;
136: return true;
137: } else {
138: ipos = -1;
139: return false;
140: }
141: }
142:
143: /** Move backwards one element.
144: * @return false iff already at beginning.
145: */
146: public boolean gotoPrevious() {
147: int prev = sequence.previousPos(ipos);
148: if (prev != -1) {
149: ipos = prev;
150: return true;
151: } else {
152: ipos = 0;
153: return false;
154: }
155: }
156:
157: /** See java.util.ListIterator. */
158: public Object previous() {
159: Object result = getPrevious();
160: if (result == Sequence.eofValue || !gotoPrevious())
161: throw new NoSuchElementException();
162: return result;
163: }
164:
165: /** See java.util.Enumeration. */
166: public final Object nextElement() {
167: return next();
168: }
169:
170: /**
171: * Get element following current position.
172: * Does not move the position, in contrast to next() method.
173: * @return EOF if at end of sequence, otherwise the value following.
174: */
175: public Object getNext() {
176: return sequence.getPosNext(getPos());
177: }
178:
179: /**
180: * Get element before the current position.
181: * Does not move the position, in contrast to previous() method.
182: * @return EOF if at beginning of sequence, otherwise the value prior.
183: */
184: public Object getPrevious() {
185: return sequence.getPosPrevious(getPos());
186: }
187:
188: /** See java.util.Iterator. */
189: public int nextIndex() {
190: return sequence.nextIndex(getPos());
191: }
192:
193: public final int fromEndIndex() {
194: return sequence.fromEndIndex(getPos());
195: }
196:
197: public int getContainingSequenceSize() {
198: return sequence.getContainingSequenceSize(getPos());
199: }
200:
201: /** See java.util.Iterator. */
202: public final int previousIndex() {
203: return sequence.nextIndex(getPos()) - 1;
204: }
205:
206: /** Tests whether the position pair has the "isAfter" property.
207: * I.e. if something is inserted at the position, will
208: * the iterator end up being after the new data?
209: * A toNext() or next() command should set isAfter() to true;
210: * a toPrevious or previous command should set isAfter() to false.
211: */
212: public boolean isAfter() {
213: return sequence.isAfterPos(getPos());
214: }
215:
216: public final void set(Object value) {
217: if (isAfter())
218: setPrevious(value);
219: else
220: setNext(value);
221: }
222:
223: public void setNext(Object value) {
224: sequence.setPosNext(getPos(), value);
225: }
226:
227: public void setPrevious(Object value) {
228: sequence.setPosPrevious(getPos(), value);
229: }
230:
231: public void remove() {
232: sequence.removePos(getPos(), isAfter() ? -1 : 1);
233: }
234:
235: public void add(Object o) {
236: setPos(sequence.addPos(getPos(), o));
237: }
238:
239: /** Get a position int "cookie" for this SeqPosition.
240: * The result can be passed to AbstractSequence's getPosNext(int),
241: * createRelativePos, and other methods.
242: * By default this is the value of ipos, but for sequences that need emore
243: * state than an ipos for efficient position, we use a PositionManager index.
244: * So this gets over-ridden in ExtPosition.
245: */
246: public int getPos() {
247: return ipos;
248: }
249:
250: public void setPos(AbstractSequence seq, int ipos) {
251: if (sequence != null)
252: sequence.releasePos(getPos());
253: this .ipos = ipos;
254: this .sequence = seq;
255: }
256:
257: public void setPos(int ipos) {
258: if (sequence != null)
259: sequence.releasePos(getPos());
260: this .ipos = ipos;
261: }
262:
263: public void set(AbstractSequence seq, int index, boolean isAfter) {
264: if (sequence != null)
265: sequence.releasePos(ipos);
266: sequence = seq;
267: ipos = seq.createPos(index, isAfter);
268: }
269:
270: public void set(SeqPosition pos) {
271: if (sequence != null)
272: sequence.releasePos(ipos);
273: sequence = pos.sequence;
274: pos.ipos = sequence.copyPos(pos.ipos);
275: }
276:
277: public void release() {
278: if (sequence != null) {
279: sequence.releasePos(getPos());
280: sequence = null;
281: }
282: }
283:
284: public void finalize() {
285: release();
286: }
287:
288: public String toString() {
289: if (sequence == null)
290: return toInfo();
291: Object item = sequence.getPosNext(ipos);
292: if (item == null)
293: return toInfo();
294: return item.toString();
295: }
296:
297: public String toInfo() {
298: StringBuffer sbuf = new StringBuffer(60);
299: sbuf.append('{');
300: if (sequence == null)
301: sbuf.append("null sequence");
302: else {
303: sbuf.append(sequence.getClass().getName());
304: sbuf.append('@');
305: sbuf.append(System.identityHashCode(sequence));
306: }
307: sbuf.append(" ipos: ");
308: sbuf.append(ipos);
309: /*
310: if (sequence instanceof TreeList)
311: {
312: sbuf.append(" index: ");
313: sbuf.append(((TreeList) sequence).posToDataIndex(ipos));
314: }
315: */
316: sbuf.append('}');
317: return sbuf.toString();
318: }
319: }
320: // This is for people using the Emacs editor:
321: // Local Variables:
322: // c-file-style: "gnu"
323: // tab-width: 8
324: // indent-tabs-mode: t
325: // End:
|