001: package net.sf.saxon.om;
002:
003: import net.sf.saxon.expr.LastPositionFinder;
004: import net.sf.saxon.expr.ReversibleIterator;
005: import net.sf.saxon.value.SequenceExtent;
006: import net.sf.saxon.value.Value;
007:
008: /**
009: * ArrayIterator is used to enumerate items held in an array.
010: * The items are always held in the correct sorted order for the sequence.
011: *
012: * @author Michael H. Kay
013: */
014:
015: public final class ArrayIterator implements AxisIterator,
016: ReversibleIterator, LastPositionFinder, LookaheadIterator,
017: GroundedIterator {
018:
019: private Item[] items;
020: private int index; // position in array of current item, zero-based
021: // set equal to end+1 when all the items required have been read.
022: private int start; // position of first item to be returned, zero-based
023: private int end; // position of first item that is NOT returned, zero-based
024: private Item current = null;
025:
026: /**
027: * Create an iterator over all the items in an array
028: *
029: * @param nodes the array (of any items, not necessarily nodes) to be
030: * processed by the iterator
031: */
032:
033: public ArrayIterator(Item[] nodes) {
034: this .items = nodes;
035: this .start = 0;
036: this .end = nodes.length;
037: index = 0;
038: }
039:
040: /**
041: * Create an iterator over a range of an array. Note that the start position is zero-based
042: *
043: * @param nodes the array (of nodes or simple values) to be processed by
044: * the iterator
045: * @param start the position of the first item to be processed
046: * (numbering from zero). Must be between zero and nodes.length-1; if not,
047: * undefined exceptions are likely to occur.
048: * @param end position of first item that is NOT returned, zero-based. Must be
049: * beween 1 and nodes.length; if not, undefined exceptions are likely to occur.
050: */
051:
052: public ArrayIterator(Item[] nodes, int start, int end) {
053: this .items = nodes;
054: this .end = end;
055: this .start = start;
056: index = start;
057: }
058:
059: /**
060: * Create a new ArrayIterator over the same items,
061: * with a different start point and end point
062: * @param min the start position (1-based) of the new ArrayIterator
063: * relative to the original
064: * @param max the end position (1-based) of the last item to be delivered
065: * by the new ArrayIterator, relative to the original. For example, min=2, max=3
066: * delivers the two items ($base[2], $base[3]). Set this to Integer.MAX_VALUE if
067: * there is no end limit.
068: */
069:
070: public SequenceIterator makeSliceIterator(int min, int max) {
071: Item[] items = getArray();
072: int currentStart = getStartPosition();
073: int currentEnd = getEndPosition();
074: if (min < 1) {
075: min = 1;
076: }
077: int newStart = currentStart + (min - 1);
078: if (newStart < currentStart) {
079: newStart = currentStart;
080: }
081: int newEnd = (max == Integer.MAX_VALUE ? currentEnd : newStart
082: + (max - min + 1));
083: if (newEnd > currentEnd) {
084: newEnd = currentEnd;
085: }
086: if (newEnd <= newStart) {
087: return EmptyIterator.getInstance();
088: }
089: return new ArrayIterator(items, newStart, newEnd);
090: }
091:
092: /**
093: * Test whether there are any more items
094: *
095: * @return true if there are more items
096: */
097: public boolean hasNext() {
098: return index < end;
099: }
100:
101: /**
102: * Get the next item in the array
103: *
104: * @return the next item in the array
105: */
106: public Item next() {
107: if (index >= end) {
108: index = end + 1;
109: current = null;
110: return null;
111: }
112: current = items[index++];
113: return current;
114: }
115:
116: /**
117: * Get the current item in the array
118: *
119: * @return the item returned by the most recent call of next()
120: */
121: public Item current() {
122: return current;
123: }
124:
125: /**
126: * Get the position of the current item in the array
127: *
128: * @return the current position (starting at 1 for the first item)
129: */
130: public int position() {
131: if (index > end) {
132: return -1;
133: }
134: return index - start;
135: }
136:
137: /**
138: * Get the number of items in the part of the array being processed
139: *
140: * @return the number of items; equivalently, the position of the last
141: * item
142: */
143: public int getLastPosition() {
144: return end - start;
145: }
146:
147: /**
148: * Get another iterator over the same items
149: *
150: * @return a new ArrayIterator
151: */
152: public SequenceIterator getAnother() {
153: return new ArrayIterator(items, start, end);
154: }
155:
156: /**
157: * Get an iterator that processes the same items in reverse order
158: *
159: * @return a new ArrayIterator
160: */
161: public SequenceIterator getReverseIterator() {
162: return new ReverseArrayIterator(items, start, end);
163: }
164:
165: /**
166: * Indicate that any nodes returned in the sequence will be atomized. This
167: * means that if it wishes to do so, the implementation can return the typed
168: * values of the nodes rather than the nodes themselves. The implementation
169: * is free to ignore this hint.
170: * @param atomizing true if the caller of this iterator will atomize any
171: * nodes that are returned, and is therefore willing to accept the typed
172: * value of the nodes instead of the nodes themselves.
173: */
174:
175: //public void setIsAtomizing(boolean atomizing) {}
176: /**
177: * Get the underlying array
178: *
179: * @return the underlying array being processed by the iterator
180: */
181:
182: public Item[] getArray() {
183: return items;
184: }
185:
186: /**
187: * Get the initial start position
188: *
189: * @return the start position of the iterator in the array (zero-based)
190: */
191:
192: public int getStartPosition() {
193: return start;
194: }
195:
196: /**
197: * Get the end position in the array
198: *
199: * @return the position in the array (zero-based) of the first item not included
200: * in the iteration
201: */
202:
203: public int getEndPosition() {
204: return end;
205: }
206:
207: /**
208: * Return a SequenceValue containing all the items in the sequence returned by this
209: * SequenceIterator
210: *
211: * @return the corresponding SequenceValue
212: */
213:
214: public Value materialize() {
215: if (start == 0 && end == items.length) {
216: return new SequenceExtent(items);
217: } else {
218: SequenceExtent e = new SequenceExtent(items);
219: return new SequenceExtent(e, start, end - start);
220: }
221: }
222:
223: /**
224: * Get properties of this iterator, as a bit-significant integer.
225: *
226: * @return the properties of this iterator. This will be some combination of
227: * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
228: * and {@link LOOKAHEAD}. It is always
229: * acceptable to return the value zero, indicating that there are no known special properties.
230: * It is acceptable for the properties of the iterator to change depending on its state.
231: */
232:
233: public int getProperties() {
234: return GROUNDED | LAST_POSITION_FINDER | LOOKAHEAD;
235: }
236:
237: }
238:
239: //
240: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
241: // you may not use this file except in compliance with the License. You may obtain a copy of the
242: // License at http://www.mozilla.org/MPL/
243: //
244: // Software distributed under the License is distributed on an "AS IS" basis,
245: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
246: // See the License for the specific language governing rights and limitations under the License.
247: //
248: // The Original Code is: all this file.
249: //
250: // The Initial Developer of the Original Code is Michael H. Kay.
251: //
252: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
253: //
254: // Contributor(s): none.
255: //
|