package php.runtime.lang.spl.iterator; import php.runtime.Memory; import php.runtime.env.Environment; import php.runtime.lang.BaseObject; import php.runtime.lang.ForeachIterator; import php.runtime.lang.spl.exception.InvalidArgumentException; import php.runtime.memory.ArrayMemory; import php.runtime.memory.LongMemory; import php.runtime.memory.ObjectMemory; import php.runtime.reflection.ClassEntity; import static php.runtime.annotation.Reflection.*; @Name("MultipleIterator") public class MultipleIterator extends BaseObject implements Iterator { public final static int MIT_NEED_ANY = 0; public final static int MIT_NEED_ALL = 1; public final static int MIT_KEYS_NUMERIC = 0; public final static int MIT_KEYS_ASSOC = 2; protected ArrayMemory iterators = new ArrayMemory(); protected int flags; public MultipleIterator(Environment env) { super(env); } public MultipleIterator(Environment env, ClassEntity clazz) { super(env, clazz); } @Signature(@Arg(value = "flags", optional = @Optional("0"))) public Memory __construct(Environment env, Memory... args) { flags = args[0].toInteger(); return Memory.NULL; } @Signature({ @Arg(value = "iterator", typeClass = "Iterator"), @Arg(value = "info", optional = @Optional("null")) }) public Memory attachIterator(Environment env, Memory... args) { Iterator iterator = args[0].toObject(Iterator.class); if (!iterator.valid(env, args).toBoolean()) { env.exception(InvalidArgumentException.class, "Iterator is not valid"); } if (args[1].isNull()) { iterators.add(args[0]); } else { if (iterators.get(args[1]) != null) { env.exception(InvalidArgumentException.class, "Iterator '" + args[1] + "' already exists"); } iterators.refOfIndex(args[1]).assign(args[0]); } return Memory.NULL; } @Signature public Memory countIterators(Environment env, Memory... args) { return LongMemory.valueOf(iterators.size()); } @Signature public Memory getFlags(Environment env, Memory... args) { return LongMemory.valueOf(flags); } @Signature(@Arg("flags")) public Memory setFlags(Environment env, Memory... args) { flags = args[0].toInteger(); return Memory.NULL; } @Override @Signature public Memory current(Environment env, Memory... args) { if (iterators.size() == 0) { return Memory.FALSE; } ArrayMemory result = new ArrayMemory(); ForeachIterator iterator = iterators.getNewIterator(env); while (iterator.next()) { Iterator el = iterator.getValue().toObject(Iterator.class); if (env.invokeMethodNoThrow(el, "valid").toBoolean()) { Memory current = env.invokeMethodNoThrow(el, "current"); if ((flags & MIT_KEYS_ASSOC) == MIT_KEYS_ASSOC) { result.put(iterator.getKey(), current); } else { result.add(current); } } else { if ((flags & MIT_NEED_ALL) == MIT_NEED_ALL) { env.exception(InvalidArgumentException.class, "One of iterators is not valid"); } } } return result.toConstant(); } @Override @Signature public Memory key(Environment env, Memory... args) { return current(env, args); } @Override @Signature public Memory next(Environment env, Memory... args) { for (Memory el : iterators) { env.invokeMethodNoThrow(el.toObject(Iterator.class), "next"); } return Memory.NULL; } @Override @Signature public Memory rewind(Environment env, Memory... args) { for (Memory el : iterators) { env.invokeMethodNoThrow(el.toObject(Iterator.class), "rewind"); } return Memory.NULL; } @Override @Signature public Memory valid(Environment env, Memory... args) { for (Memory el : iterators) { if (env.invokeMethodNoThrow(el.toObject(Iterator.class), "valid").toBoolean()) { if ((flags & MIT_NEED_ALL) != flags) { return Memory.TRUE; } } else { if ((flags & MIT_NEED_ALL) == flags) { return Memory.FALSE; } } } return Memory.TRUE; } @Override public ForeachIterator getNewIterator(Environment env, boolean getReferences, boolean getKeyReferences) { return ObjectMemory.valueOf(this).getNewIterator(env, getReferences, getKeyReferences); } @Override public ForeachIterator getNewIterator(Environment env) { return ObjectMemory.valueOf(this).getNewIterator(env); } }