001: package net.sf.saxon.value;
002:
003: import net.sf.saxon.expr.ExpressionTool;
004: import net.sf.saxon.expr.LastPositionFinder;
005: import net.sf.saxon.expr.StaticProperty;
006: import net.sf.saxon.expr.XPathContext;
007: import net.sf.saxon.om.*;
008: import net.sf.saxon.trans.XPathException;
009: import net.sf.saxon.type.AnyItemType;
010: import net.sf.saxon.type.ItemType;
011: import net.sf.saxon.type.Type;
012: import net.sf.saxon.type.TypeHierarchy;
013:
014: import java.util.ArrayList;
015: import java.util.List;
016:
017: /**
018: * A sequence value implemented extensionally. That is, this class represents a sequence
019: * by allocating memory to each item in the sequence.
020: */
021:
022: public final class SequenceExtent extends Value {
023: private Item[] value;
024: private int start = 0; // zero-based offset of the start
025: private int end; // the 0-based index of the first item that is NOT included
026: private ItemType itemType = null; // memoized
027:
028: // private static int instances = 0;
029:
030: /**
031: * Construct an sequence from an array of items. Note, the array of items is used as is,
032: * which means the caller must not subsequently change its contents.
033: *
034: * @param items the array of items to be included in the sequence
035: */
036:
037: public SequenceExtent(Item[] items) {
038: this .value = items;
039: end = items.length;
040: }
041:
042: /**
043: * Construct a SequenceExtent from part of an array of items
044: * @param value The array
045: * @param start zero-based offset of the first item in the array
046: * that is to be included in the new SequenceExtent
047: * @param length The number of items in the new SequenceExtent
048: */
049:
050: public SequenceExtent(Item[] value, int start, int length) {
051: this .value = value;
052: this .start = start;
053: this .end = this .start + length;
054: }
055:
056: /**
057: * Construct a SequenceExtent as a view of another SequenceExtent
058: * @param ext The existing SequenceExtent
059: * @param start zero-based offset of the first item in the existing SequenceExtent
060: * that is to be included in the new SequenceExtent
061: * @param length The number of items in the new SequenceExtent
062: */
063:
064: public SequenceExtent(SequenceExtent ext, int start, int length) {
065: this .value = ext.value;
066: this .start = ext.start + start;
067: this .end = this .start + length;
068: }
069:
070: /**
071: * Construct a SequenceExtent from a List. The members of the list must all
072: * be Items
073: *
074: * @param list the list of items to be included in the sequence
075: */
076:
077: public SequenceExtent(List list) {
078: copyList(list);
079: }
080:
081: private void copyList(List list) {
082: value = new Item[list.size()];
083: for (int i = 0; i < list.size(); i++) {
084: value[i] = (Item) list.get(i);
085: }
086: end = list.size();
087: }
088:
089: /**
090: * Construct a sequence containing all the items in a SequenceIterator.
091: *
092: * @exception net.sf.saxon.trans.XPathException if reading the items using the
093: * SequenceIterator raises an error
094: * @param iter The supplied sequence of items. This must be positioned at
095: * the start, so that hasNext() returns true if there are any nodes in
096: * the node-set, and next() returns the first node.
097: */
098:
099: public SequenceExtent(SequenceIterator iter) throws XPathException {
100: if ((iter.getProperties() & SequenceIterator.LAST_POSITION_FINDER) == 0) {
101: List list = new ArrayList(20);
102: while (true) {
103: Item it = iter.next();
104: if (it == null) {
105: break;
106: }
107: list.add(it);
108: }
109: copyList(list);
110: } else {
111: end = ((LastPositionFinder) iter).getLastPosition();
112: value = new Item[end];
113: int i = 0;
114: while (true) {
115: Item it = iter.next();
116: if (it == null) {
117: break;
118: }
119: value[i++] = it;
120: }
121: }
122: }
123:
124: /**
125: * Factory method to make a Value holding the contents of any SequenceIterator
126: */
127:
128: public static Value makeSequenceExtent(SequenceIterator iter)
129: throws XPathException {
130: if ((iter.getProperties() & SequenceIterator.GROUNDED) != 0) {
131: return ((GroundedIterator) iter).materialize();
132: }
133: //iter = new MappingIterator(iter, new UserFunctionCall.Flattener(), null);
134: return new SequenceExtent(iter);
135: }
136:
137: /**
138: * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process().
139: * This method indicates which of these methods is preferred.
140: */
141:
142: public int getImplementationMethod() {
143: return ITERATE_METHOD;
144: }
145:
146: /**
147: * Simplify this SequenceExtent
148: */
149:
150: public Value simplify() {
151: int n = getLength();
152: if (n == 0) {
153: return EmptySequence.getInstance();
154: } else if (n == 1) {
155: return Value.asValue(itemAt(0));
156: } else {
157: return this ;
158: }
159: }
160:
161: /**
162: * Reduce a value to its simplest form. If the value is a closure or some other form of deferred value
163: * such as a FunctionCallPackage, then it is reduced to a SequenceExtent. If it is a SequenceExtent containing
164: * a single item, then it is reduced to that item. One consequence that is exploited by class FilterExpression
165: * is that if the value is a singleton numeric value, then the result will be an instance of NumericValue
166: */
167:
168: public Value reduce() {
169: return simplify();
170: }
171:
172: /**
173: * Get the number of items in the sequence
174: *
175: * @return the number of items in the sequence
176: */
177:
178: public int getLength() {
179: return end - start;
180: }
181:
182: /**
183: * Determine the cardinality
184: *
185: * @return the cardinality of the sequence, using the constants defined in
186: * net.sf.saxon.value.Cardinality
187: * @see net.sf.saxon.value.Cardinality
188: */
189:
190: public int getCardinality() {
191: switch (end - start) {
192: case 0:
193: return StaticProperty.EMPTY;
194: case 1:
195: return StaticProperty.EXACTLY_ONE;
196: default:
197: return StaticProperty.ALLOWS_ONE_OR_MORE;
198: }
199: }
200:
201: /**
202: * Get the (lowest common) item type
203: *
204: * @return integer identifying an item type to which all the items in this
205: * sequence conform
206: * @param th
207: */
208:
209: public ItemType getItemType(TypeHierarchy th) {
210: if (itemType != null) {
211: // only calculate it the first time
212: return itemType;
213: }
214: if (end == start) {
215: itemType = AnyItemType.getInstance();
216: } else {
217: itemType = Type.getItemType(value[start]);
218: for (int i = start + 1; i < end; i++) {
219: if (itemType == AnyItemType.getInstance()) {
220: // make a quick exit
221: return itemType;
222: }
223: itemType = Type.getCommonSuperType(itemType, Type
224: .getItemType(value[i]), th);
225: }
226: }
227: return itemType;
228: }
229:
230: /**
231: * Get the n'th item in the sequence (starting with 0 as the first item)
232: *
233: * @param n the position of the required item
234: * @return the n'th item in the sequence
235: */
236:
237: public Item itemAt(int n) {
238: if (n < 0 || n >= getLength()) {
239: return null;
240: } else {
241: return value[start + n];
242: }
243: }
244:
245: /**
246: * Swap two items (needed to support sorting)
247: *
248: * @param a the position of the first item to be swapped
249: * @param b the position of the second item to be swapped
250: */
251:
252: public void swap(int a, int b) {
253: Item temp = value[start + a];
254: value[start + a] = value[start + b];
255: value[start + b] = temp;
256: }
257:
258: /**
259: * Return an iterator over this sequence.
260: *
261: * @param context dynamic evaluation context; not used in this
262: * implementation of the method
263: * @return the required SequenceIterator, positioned at the start of the
264: * sequence
265: */
266:
267: public SequenceIterator iterate(XPathContext context) {
268: return new ArrayIterator(value, start, end);
269: }
270:
271: /**
272: * Return an enumeration of this sequence in reverse order (used for reverse axes)
273: *
274: * @return an AxisIterator that processes the items in reverse order
275: */
276:
277: public AxisIterator reverseIterate() {
278: return new ReverseArrayIterator(value, start, end);
279: }
280:
281: /**
282: * Get the effective boolean value
283: */
284:
285: public boolean effectiveBooleanValue(XPathContext context)
286: throws XPathException {
287: int len = getLength();
288: if (len == 0) {
289: return false;
290: } else if (value[0] instanceof NodeInfo) {
291: return true;
292: } else if (len > 1) {
293: // this is a type error - reuse the error messages
294: return ExpressionTool
295: .effectiveBooleanValue(iterate(context));
296: } else {
297: return ((AtomicValue) value[0])
298: .effectiveBooleanValue(context);
299: }
300: }
301:
302: }
303:
304: //
305: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
306: // you may not use this file except in compliance with the License. You may obtain a copy of the
307: // License at http://www.mozilla.org/MPL/
308: //
309: // Software distributed under the License is distributed on an "AS IS" basis,
310: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
311: // See the License for the specific language governing rights and limitations under the License.
312: //
313: // The Original Code is: all this file.
314: //
315: // The Initial Developer of the Original Code is Michael H. Kay.
316: //
317: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
318: //
319: // Contributor(s): none.
320: //
|