1 package net.sf.saxon.value; 2 3 import net.sf.saxon.Controller; 4 import net.sf.saxon.event.SequenceOutputter; 5 import net.sf.saxon.event.SequenceReceiver; 6 import net.sf.saxon.event.TeeOutputter; 7 import net.sf.saxon.expr.LastPositionFinder; 8 import net.sf.saxon.expr.XPathContext; 9 import net.sf.saxon.om.*; 10 import net.sf.saxon.trans.DynamicError; 11 import net.sf.saxon.trans.XPathException; 12 13 import java.util.List ; 14 15 48 49 public class MemoClosure extends Closure { 50 51 private Item[] reservoir = null; 52 private int used; 53 private int state; 54 55 private static final int UNREAD = 0; 57 58 private static final int MAYBE_MORE = 1; 61 62 private static final int ALL_READ = 3; 64 65 private static final int BUSY = 4; 68 69 private static final int EMPTY = 5; 71 72 75 76 public MemoClosure() { 77 } 78 79 85 86 public SequenceIterator iterate(XPathContext context) throws XPathException { 87 88 switch (state) { 89 case UNREAD: 90 state = BUSY; 91 inputIterator = expression.iterate(savedXPathContext); 92 if (inputIterator instanceof EmptyIterator) { 93 state = EMPTY; 94 return inputIterator; 95 } 96 reservoir = new Item[50]; 102 used = 0; 103 state = MAYBE_MORE; 104 return new ProgressiveIterator(); 105 106 case MAYBE_MORE: 107 return new ProgressiveIterator(); 108 109 case ALL_READ: 110 return new ArrayIterator(reservoir, 0, used); 111 112 case BUSY: 113 throw new DynamicError("Attempt to access a lazily-evaluated variable while it is being evaluated"); 115 116 case EMPTY: 117 return EmptyIterator.getInstance(); 118 119 default: 120 throw new IllegalStateException ("Unknown iterator state"); 121 122 } 123 } 124 125 131 132 public void process(XPathContext context) throws XPathException { 133 if (state == EMPTY) { 137 return; } 139 if (reservoir != null) { 140 SequenceIterator iter = iterate(context); 141 SequenceReceiver out = context.getReceiver(); 142 while (true) { 143 Item it = iter.next(); 144 if (it==null) break; 145 out.append(it, 0, NodeInfo.ALL_NAMESPACES); 146 } 147 } else { 148 Controller controller = context.getController(); 149 XPathContext c2 = savedXPathContext.newMinorContext(); 150 SequenceOutputter seq = new SequenceOutputter(); 154 seq.setPipelineConfiguration(controller.makePipelineConfiguration()); 155 seq.open(); 156 TeeOutputter tee = new TeeOutputter(context.getReceiver(), seq); 157 tee.setPipelineConfiguration(controller.makePipelineConfiguration()); 158 c2.setTemporaryReceiver(tee); 159 160 expression.process(c2); 161 162 seq.close(); 163 List list = seq.getList(); 164 if (list.size() == 0) { 165 state = EMPTY; 166 } else { 167 reservoir = new Item[list.size()]; 168 reservoir = (Item[])list.toArray(reservoir); 169 used = list.size(); 170 state = ALL_READ; 171 } 172 savedXPathContext = null; 174 } 177 178 } 179 180 184 185 public Item itemAt(int n) throws XPathException { 186 if (n < 0) { 187 return null; 188 } 189 if (reservoir != null && n < used) { 190 return reservoir[n]; 191 } 192 if (state == ALL_READ || state == EMPTY) { 193 return null; 194 } 195 if (state == UNREAD) { 196 return super.itemAt(n); 197 } 199 int diff = n - used + 1; 201 while (diff-- > 0) { 202 Item i = inputIterator.next(); 203 if (i == null) { 204 state = ALL_READ; 205 condense(); 206 return itemAt(n); 207 } 208 append(i); 209 state = MAYBE_MORE; 210 } 211 return reservoir[n]; 212 } 213 214 217 218 public int getLength() throws XPathException { 219 if (state == ALL_READ) { 220 return used; 221 } else if (state == EMPTY) { 222 return 0; 223 } else { 224 return super.getLength(); 225 } 226 } 227 228 231 232 private void append(Item item) { 233 if (used >= reservoir.length) { 234 Item[] r2 = new Item[used*2]; 235 System.arraycopy(reservoir, 0, r2, 0, used); 236 reservoir = r2; 237 } 238 reservoir[used++] = item; 239 } 240 241 244 245 private void condense() { 246 if (reservoir.length - used > 30) { 247 Item[] r2 = new Item[used]; 248 System.arraycopy(reservoir, 0, r2, 0, used); 249 reservoir = r2; 250 } 251 savedXPathContext = null; 253 } 256 257 262 263 public final class ProgressiveIterator implements SequenceIterator, LastPositionFinder, GroundedIterator { 264 265 int position = -1; 268 public ProgressiveIterator() { 269 270 } 271 272 public Item next() throws XPathException { 273 if (position == -2) { return null; 275 } 276 if (++position < used) { 277 return reservoir[position]; 278 } else { 281 Item i = inputIterator.next(); 282 if (i == null) { 283 state = ALL_READ; 284 condense(); 285 position = -2; 287 return null; 288 } 289 position = used; 290 append(i); 291 state = MAYBE_MORE; 292 return i; 293 } 294 } 295 296 public Item current() { 297 if (position < 0) { 298 return null; 299 } 300 return reservoir[position]; 301 } 302 303 public int position() { 304 return position + 1; } 306 307 public SequenceIterator getAnother() { 308 return new ProgressiveIterator(); 309 } 310 311 314 315 public int getLastPosition() throws XPathException { 316 if (state == ALL_READ) { 317 return used; 318 } else if (state == EMPTY) { 319 return 0; 320 } else { 321 int savePos = position; 323 while (true) { 325 Item item = next(); 326 if (item == null) { 327 break; 328 } 329 } 330 position = savePos; 332 return used; 334 } 335 } 336 337 343 344 public Value materialize() throws XPathException { 345 if (state == ALL_READ) { 346 return new SequenceExtent(reservoir); 347 } else if (state == EMPTY) { 348 return EmptySequence.getInstance(); 349 } 350 return new SequenceExtent(iterate(null)); 351 352 } 353 354 361 362 public int getProperties() { 363 if (state == EMPTY || state == ALL_READ) { 364 return GROUNDED | LAST_POSITION_FINDER; 365 } else { 366 return 0; 367 } 368 } 369 } 370 371 } 372 373 | Popular Tags |