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