package php.runtime.ext.core; import php.runtime.Memory; import php.runtime.annotation.Runtime; import php.runtime.env.Environment; import php.runtime.env.TraceInfo; import php.runtime.ext.support.compile.FunctionsContainer; import php.runtime.lang.ForeachIterator; import php.runtime.lang.spl.Countable; import php.runtime.memory.ArrayMemory; import php.runtime.memory.LongMemory; import php.runtime.memory.ObjectMemory; import java.util.HashSet; import java.util.Set; public class ArrayFunctions extends FunctionsContainer { private static int recursive_count(Environment env, TraceInfo trace, ArrayMemory array, Set<Integer> used){ ForeachIterator iterator = array.foreachIterator(false, false); int size = array.size(); while (iterator.next()){ Memory el = iterator.getValue(); if (el.isArray()){ if (used == null) used = new HashSet<>(); int pointer = el.getPointer(); if (!used.add(pointer)){ env.warning(trace, "recursion detected"); } else { size += recursive_count(env, trace, array, used); } used.remove(pointer); } } return size; } @Runtime.Immutable public static Memory count(Environment env, TraceInfo trace, Memory var, int mode){ switch (var.type){ case ARRAY: if (mode == 1){ return LongMemory.valueOf(recursive_count(env, trace, var.toValue(ArrayMemory.class), null)); } else return LongMemory.valueOf(var.toValue(ArrayMemory.class).size()); case NULL: return Memory.CONST_INT_0; case OBJECT: ObjectMemory objectMemory = var.toValue(ObjectMemory.class); if (objectMemory.value instanceof Countable){ env.pushCall(objectMemory.value, "count"); try { long size = ((Countable) objectMemory.value).count(env).toLong(); return LongMemory.valueOf(size); } finally { env.popCall(); } } else { return Memory.CONST_INT_1; } default: return Memory.CONST_INT_1; } } @Runtime.Immutable public static Memory count(Environment env, TraceInfo trace, Memory var){ return count(env, trace, var, 0); } @Runtime.Immutable public static Memory sizeof(Environment env, TraceInfo trace, Memory var){ return count(env, trace, var, 0); } @Runtime.Immutable public static Memory sizeof(Environment env, TraceInfo trace, Memory var, int mode){ return count(env, trace, var, mode); } }