package php.runtime.lang; import php.runtime.Memory; import php.runtime.env.Environment; import php.runtime.env.TraceInfo; import php.runtime.memory.LongMemory; import php.runtime.memory.StringMemory; import java.util.Iterator; import java.util.Map; abstract public class ForeachIterator implements Iterable<Memory> { protected Object currentKey; protected Memory currentKeyMemory; protected Memory currentValue; protected boolean init = false; protected final boolean getReferences; protected final boolean getKeyReferences; protected final boolean withPrevious; protected boolean plainReferences = false; abstract protected boolean init(); abstract protected boolean nextValue(); abstract protected boolean prevValue(); protected TraceInfo trace = TraceInfo.UNKNOWN; public static ForeachIterator of(final Environment env, final Map map) { return new ForeachIterator(false, false, false) { private Iterator<Map.Entry<Object, Object>> entries; @Override protected boolean init() { reset(); return !map.isEmpty(); } @Override protected boolean nextValue() { if (entries.hasNext()) { Map.Entry<Object, Object> entry = entries.next(); currentKey = entry.getKey(); currentKeyMemory = currentKey == null ? Memory.NULL : StringMemory.valueOf(currentKey.toString()); currentValue = Memory.wrap(env, entry.getValue()); if (!getReferences) { currentValue = currentValue.toValue(); } return true; } return false; } @Override protected boolean prevValue() { return false; } @Override public void reset() { entries = map.entrySet().iterator(); } }; } public static ForeachIterator of(final Environment env, final Iterable iterable) { return new ForeachIterator(false, false, false) { protected Iterator iterator; @Override protected boolean init() { iterator = iterable.iterator(); currentKeyMemory = LongMemory.CONST_INT_M1; currentKey = currentKeyMemory.toLong(); return true; } @Override protected boolean nextValue() { if (!iterator.hasNext()) { return false; } Object next = iterator.next(); currentKeyMemory = currentKeyMemory == null ? Memory.CONST_INT_0 : currentKeyMemory.inc(); currentKey = currentKeyMemory.toLong(); currentValue = Memory.wrap(env, next); return true; } @Override protected boolean prevValue() { return false; } @Override public void reset() { iterator = iterable.iterator(); } }; } public ForeachIterator(boolean getReferences, boolean getKeyReferences, boolean withPrevious) { this.getReferences = getReferences; this.withPrevious = withPrevious; this.getKeyReferences = getKeyReferences; } public void setPlainReferences(boolean plainReferences) { this.plainReferences = plainReferences; } public boolean prev() { currentKeyMemory = null; if (!init || !withPrevious) { this.currentKey = null; this.currentValue = null; return false; } else return prevValue(); } public boolean next() { currentKeyMemory = null; if (!init) { init = true; if (!init()) return false; } return nextValue(); } public boolean end() { return false; } public Object getKey() { return currentKey; } public String getStringKey() { Object key = getKey(); return key == null ? null : key.toString(); } abstract public void reset(); public boolean isLongKey() { return currentKey instanceof Long || (currentKey instanceof Memory && ((Memory) currentKey).isNumber()); } public Memory getMemoryKey() { if (currentKeyMemory != null) return currentKeyMemory; if (currentKey instanceof String) return currentKeyMemory = new StringMemory((String) currentKey); if (currentKey instanceof Long) return currentKeyMemory = LongMemory.valueOf((Long) currentKey); if (currentKey instanceof Memory) return currentKeyMemory = (Memory) currentKey; return currentKeyMemory = Memory.NULL; } public Memory getValue() { return currentValue; } public TraceInfo getTrace() { return trace; } public void setTrace(TraceInfo trace) { this.trace = trace; } @Override public Iterator<Memory> iterator() { return new Iterator<Memory>() { protected Boolean hasNext; @Override public boolean hasNext() { if (hasNext == null) { hasNext = ForeachIterator.this.next(); } return hasNext; } @Override public Memory next() { if (hasNext != null) { hasNext = null; return ForeachIterator.this.getValue(); } else { ForeachIterator.this.next(); return ForeachIterator.this.getValue(); } } @Override public void remove() { throw new IllegalStateException("Unsupported remove() method"); } }; } }