001: package net.sf.saxon.value;
002:
003: import net.sf.saxon.expr.ExpressionTool;
004: import net.sf.saxon.expr.StaticProperty;
005: import net.sf.saxon.expr.XPathContext;
006: import net.sf.saxon.om.Item;
007: import net.sf.saxon.om.ListIterator;
008: import net.sf.saxon.om.NodeInfo;
009: import net.sf.saxon.om.SequenceIterator;
010: import net.sf.saxon.trans.XPathException;
011: import net.sf.saxon.type.AnyItemType;
012: import net.sf.saxon.type.ItemType;
013: import net.sf.saxon.type.Type;
014: import net.sf.saxon.type.TypeHierarchy;
015:
016: import java.util.List;
017:
018: /**
019: * A sequence value implemented extensionally using an extensible List whose leading part can be shared
020: * with other sequence values. The list can be appended to by other users (at most one other user!),
021: * but the items within the range used by this sequence value cannot be modified.
022: */
023:
024: public final class ShareableSequence extends Value {
025: private List list;
026: private int end; // the 0-based index of the first item that is NOT included
027: private ItemType itemType = null; // memoized
028:
029: /**
030: * Construct an sequence from an array of items. Note, the list of items is used as is,
031: * which means the caller must not subsequently change its contents; however it is permitted
032: * to subsequently append items to the list (indeed, that is the raison d'etre of this class)
033: *
034: * @param list the list of items to be included in the sequence
035: */
036:
037: public ShareableSequence(List list) {
038: //System.err.println("** Using shareable sequence **");
039: this .list = list;
040: this .end = list.size();
041: }
042:
043: /**
044: * Determine whether another value can share this list. This is true provided the list has
045: * not already been extended by another value.
046: */
047:
048: public boolean isShareable() {
049: return list.size() == end;
050: }
051:
052: /**
053: * Get the underlying list
054: */
055:
056: public List getList() {
057: return list;
058: }
059:
060: /**
061: * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process().
062: * This method indicates which of these methods is preferred.
063: */
064:
065: public int getImplementationMethod() {
066: return ITERATE_METHOD;
067: }
068:
069: /**
070: * Simplify this value
071: */
072:
073: public Value simplify() {
074: int n = getLength();
075: if (n == 0) {
076: return EmptySequence.getInstance();
077: } else if (n == 1) {
078: return Value.asValue(itemAt(0));
079: } else {
080: return this ;
081: }
082: }
083:
084: /**
085: * Reduce a value to its simplest form. If the value is a closure or some other form of deferred value
086: * such as a FunctionCallPackage, then it is reduced to a SequenceExtent. If it is a SequenceExtent containing
087: * a single item, then it is reduced to that item. One consequence that is exploited by class FilterExpression
088: * is that if the value is a singleton numeric value, then the result will be an instance of NumericValue
089: */
090:
091: public Value reduce() {
092: return simplify();
093: }
094:
095: /**
096: * Get the number of items in the sequence
097: *
098: * @return the number of items in the sequence
099: */
100:
101: public int getLength() {
102: return end;
103: }
104:
105: /**
106: * Determine the cardinality
107: *
108: * @return the cardinality of the sequence, using the constants defined in
109: * net.sf.saxon.value.Cardinality
110: * @see Cardinality
111: */
112:
113: public int getCardinality() {
114: switch (end) {
115: case 0:
116: return StaticProperty.EMPTY;
117: case 1:
118: return StaticProperty.EXACTLY_ONE;
119: default:
120: return StaticProperty.ALLOWS_ONE_OR_MORE;
121: }
122: }
123:
124: /**
125: * Get the (lowest common) item type
126: *
127: * @return integer identifying an item type to which all the items in this
128: * sequence conform
129: * @param th
130: */
131:
132: public ItemType getItemType(TypeHierarchy th) {
133: if (itemType != null) {
134: // only calculate it the first time
135: return itemType;
136: }
137: if (end == 0) {
138: itemType = AnyItemType.getInstance();
139: } else {
140: itemType = Type.getItemType(itemAt(0));
141: for (int i = 1; i < end; i++) {
142: if (itemType == AnyItemType.getInstance()) {
143: // make a quick exit
144: return itemType;
145: }
146: itemType = Type.getCommonSuperType(itemType, Type
147: .getItemType(itemAt(i)), th);
148: }
149: }
150: return itemType;
151: }
152:
153: /**
154: * Get the n'th item in the sequence (starting with 0 as the first item)
155: *
156: * @param n the position of the required item
157: * @return the n'th item in the sequence
158: */
159:
160: public Item itemAt(int n) {
161: if (n < 0 || n >= getLength()) {
162: return null;
163: } else {
164: return (Item) list.get(n);
165: }
166: }
167:
168: /**
169: * Return an iterator over this sequence.
170: *
171: * @param context dynamic evaluation context; not used in this
172: * implementation of the method
173: * @return the required SequenceIterator, positioned at the start of the
174: * sequence
175: */
176:
177: public SequenceIterator iterate(XPathContext context) {
178: return new ListIterator(list, end);
179: }
180:
181: /**
182: * Get the effective boolean value
183: */
184:
185: public boolean effectiveBooleanValue(XPathContext context)
186: throws XPathException {
187: int len = getLength();
188: if (len == 0) {
189: return false;
190: } else if (itemAt(0) instanceof NodeInfo) {
191: return true;
192: } else if (len > 1) {
193: // this is a type error - reuse the error messages
194: return ExpressionTool
195: .effectiveBooleanValue(iterate(context));
196: } else {
197: return ((AtomicValue) itemAt(0))
198: .effectiveBooleanValue(context);
199: }
200: }
201:
202: }
203:
204: //
205: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
206: // you may not use this file except in compliance with the License. You may obtain a copy of the
207: // License at http://www.mozilla.org/MPL/
208: //
209: // Software distributed under the License is distributed on an "AS IS" basis,
210: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
211: // See the License for the specific language governing rights and limitations under the License.
212: //
213: // The Original Code is: all this file.
214: //
215: // The Initial Developer of the Original Code is Michael H. Kay.
216: //
217: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
218: //
219: // Contributor(s): none.
220: //
|