package php.runtime.ext.core.classes.lib; import php.runtime.Memory; import php.runtime.annotation.Reflection.Name; import php.runtime.annotation.Reflection.Signature; import php.runtime.env.Environment; import php.runtime.env.TraceInfo; import php.runtime.invoke.Invoker; import php.runtime.lang.BaseObject; import php.runtime.lang.ForeachIterator; import php.runtime.lang.spl.Countable; import php.runtime.lang.spl.Traversable; import php.runtime.memory.ArrayMemory; import php.runtime.memory.LongMemory; import php.runtime.memory.ObjectMemory; import php.runtime.memory.StringMemory; import php.runtime.reflection.ClassEntity; import java.util.*; import static php.runtime.annotation.Reflection.Nullable; @Name("php\\util\\Shared") public class SharedUtils extends BaseObject { protected static final Map<String, SharedValue> globalValue = new HashMap<String, SharedValue>(); public SharedUtils(Environment env, ClassEntity clazz) { super(env, clazz); } @Signature private void __construct() { } @Signature public static void resetAll() { synchronized (globalValue) { globalValue.clear(); } } @Signature public static SharedValue reset(String name) { synchronized (globalValue) { return globalValue.remove(name); } } @Signature public static SharedValue value(Environment env, String name) throws Throwable { return value(env, name, null); } @Signature public static SharedValue value(Environment env, String name, @Nullable Invoker creator) throws Throwable { SharedValue value = globalValue.get(name); if (value != null) { return value; } synchronized (globalValue) { value = new SharedValue(env, (Memory) null); SharedValue oldValue = globalValue.get(name); if (oldValue != null) { return oldValue; } if (creator != null) { value.set(creator.call()); } globalValue.put(name, value); return value; } } @Name("php\\util\\SharedMemory") abstract public static class SharedMemory extends BaseObject { public SharedMemory(Environment env) { super(env); } public SharedMemory(Environment env, ClassEntity clazz) { super(env, clazz); } @Signature synchronized public Memory synchronize(Invoker sync) throws Throwable { if (sync.getArgumentCount() > 0) { return sync.call(ObjectMemory.valueOf(this)); } else { return sync.call(); } } } @Name("php\\util\\SharedValue") public static class SharedValue extends SharedMemory { protected Memory value = null; public SharedValue(Environment env, Memory value) { super(env); this.value = value; } public SharedValue(Environment env, ClassEntity clazz) { super(env, clazz); } @Signature synchronized public void __construct() { value = null; } @Signature synchronized public void __construct(Memory value) { this.value = value; } @Signature synchronized public Memory __debugInfo(Environment env, Memory... args) { ArrayMemory info = new ArrayMemory(); info.refOfIndex("*value").assign(value); return info.toConstant(); } @Signature synchronized public boolean isEmpty() { return value == null; } @Signature synchronized public Memory get() { return value == null ? Memory.UNDEFINED : value; } @Signature public Memory set(Memory value) { return set(value, true); } @Signature synchronized public Memory set(Memory value, boolean override) { Memory result = this.value; if (value == null || override) { this.value = value; } return result == null ? Memory.UNDEFINED : result; } @Signature synchronized public Memory remove() { Memory result = value; value = null; return result == null ? Memory.UNDEFINED : result; } @Signature synchronized public Memory getAndSet(Invoker update) throws Throwable { Memory result = value == null ? Memory.UNDEFINED : value; value = update.call(result); return result; } @Signature synchronized public Memory setAndGet(Invoker update) throws Throwable { value = value == null ? Memory.UNDEFINED : value; value = update.call(value); return value; } @Signature synchronized public Memory synchronize(Invoker sync) throws Throwable { if (sync.getArgumentCount() > 0) { return sync.call(ObjectMemory.valueOf(this)); } else { return sync.call(); } } @Signature synchronized public void __clone(Environment env, TraceInfo trace) throws Throwable { if (value == null) { this.value = null; } else if (value.isObject()) { this.value = value.clone(env, trace); } else { this.value = value.toImmutable(); } } } @Name("php\\util\\SharedCollection") abstract public static class SharedCollection extends SharedMemory implements Countable, Traversable { public SharedCollection(Environment env) { super(env); } public SharedCollection(Environment env, ClassEntity clazz) { super(env, clazz); } @Signature abstract public boolean isEmpty(); @Signature abstract public void clear(); } @Name("php\\util\\SharedQueue") public static class SharedQueue extends SharedCollection { protected Queue<Memory> queue; public SharedQueue(Environment env, Queue<Memory> queue) { super(env); this.queue = queue; } public SharedQueue(Environment env, ClassEntity clazz) { super(env, clazz); } @Signature public void __construct() { queue = new LinkedList<Memory>(); } @Signature synchronized public Memory __debugInfo(Environment env, Memory... args) { ArrayMemory info = new ArrayMemory(); info.refOfIndex("*queue").assign(ArrayMemory.ofCollection(queue)); return info.toConstant(); } @Signature public void __construct(ForeachIterator iterator) { queue = new LinkedList<Memory>(); while (iterator.next()) { queue.add(iterator.getValue().toImmutable()); } } @Signature synchronized public boolean isEmpty() { return queue.isEmpty(); } @Override @Signature synchronized public void clear() { queue.clear(); } @Signature synchronized public boolean add(Memory value) { return queue.offer(value); } @Signature synchronized public Memory remove() { return queue.remove(); } @Signature synchronized public Memory peek() { return queue.peek(); } @Signature synchronized public Memory poll() { return queue.poll(); } @Override @Signature synchronized public Memory count(Environment env, Memory... args) { return LongMemory.valueOf(queue.size()); } @Override synchronized public ForeachIterator getNewIterator(Environment env, boolean getReferences, boolean getKeyReferences) { final Object mutex = this; return new ForeachIterator(getReferences, getKeyReferences, false) { private Iterator<Memory> iterator; protected int index; @Override protected boolean init() { reset(); synchronized (mutex) { return !queue.isEmpty(); } } @Override protected boolean nextValue() { synchronized (mutex) { if (iterator.hasNext()) { index += 1; currentKeyMemory = LongMemory.valueOf(index); currentKey = currentKeyMemory; currentValue = iterator.next(); if (!getReferences) { currentValue = currentValue.toValue(); } return true; } else { return false; } } } @Override protected boolean prevValue() { return false; } @Override public void reset() { synchronized (mutex) { currentKeyMemory = Memory.CONST_INT_M1; currentKey = currentKeyMemory; index = -1; iterator = queue.iterator(); } } }; } @Override public ForeachIterator getNewIterator(Environment env) { return getNewIterator(env, false, false); } } @Name("php\\util\\SharedStack") public static class SharedStack extends SharedCollection { protected Stack<Memory> stack; public SharedStack(Environment env, Stack<Memory> stack) { super(env); this.stack = stack; } public SharedStack(Environment env, ClassEntity clazz) { super(env, clazz); } @Signature public void __construct(ForeachIterator iterator) { stack = new Stack<Memory>(); while (iterator.next()) { stack.push(iterator.getValue().toImmutable()); } } @Signature public void __construct() { stack = new Stack<Memory>(); } @Signature synchronized public Memory __debugInfo(Environment env, Memory... args) { ArrayMemory info = new ArrayMemory(); info.refOfIndex("*stack").assign(ArrayMemory.ofCollection(stack)); return info.toConstant(); } @Override @Signature synchronized public Memory count(Environment env, Memory... args) { return LongMemory.valueOf(stack.size()); } @Signature synchronized public Memory push(Memory arg) { return stack.push(arg); } @Signature synchronized public boolean isEmpty() { return stack.empty(); } @Signature synchronized public Memory pop() { if (stack.empty()) { return Memory.NULL; } return stack.pop(); } @Signature synchronized public Memory peek() { if (stack.empty()) { return Memory.NULL; } return stack.peek(); } @Signature synchronized public void clear() { stack.clear(); } @Signature synchronized public void __clone() { Stack<Memory> old = this.stack; this.stack = new Stack<Memory>(); stack.addAll(old); } @Override synchronized public ForeachIterator getNewIterator(Environment env, boolean getReferences, boolean getKeyReferences) { final Object mutex = this; return new ForeachIterator(getReferences, getKeyReferences, false) { protected Iterator<Memory> iterator; protected int index; @Override protected boolean init() { reset(); synchronized (mutex) { return !stack.isEmpty(); } } @Override protected boolean nextValue() { synchronized (mutex) { if (iterator.hasNext()) { index += 1; currentKeyMemory = LongMemory.valueOf(index); currentKey = currentKeyMemory; currentValue = iterator.next(); if (!getReferences) { currentValue = currentValue.toValue(); } return true; } else { return false; } } } @Override protected boolean prevValue() { return false; } @Override public void reset() { synchronized (mutex) { index = -1; currentKeyMemory = Memory.CONST_INT_M1; currentKey = currentKeyMemory; iterator = stack.iterator(); } } }; } @Override public ForeachIterator getNewIterator(Environment env) { return getNewIterator(env, false, false); } } @Name("php\\util\\SharedMap") public static class SharedMap extends SharedCollection { protected Map<String, Memory> map; public SharedMap(Environment env, Map<String, Memory> map) { super(env); this.map = map; } public SharedMap(Environment env, ClassEntity clazz) { super(env, clazz); } @Signature public void __construct(ForeachIterator iterator) { map = new LinkedHashMap<String, Memory>(); while (iterator.next()) { map.put(iterator.getKey().toString(), iterator.getValue().toImmutable()); } } @Signature public void __construct() { map = new LinkedHashMap<String, Memory>(); } @Signature synchronized public Memory __debugInfo(Environment env, Memory... args) { ArrayMemory info = new ArrayMemory(); info.refOfIndex("*map").assign(ArrayMemory.ofMap(map)); return info.toConstant(); } @Override @Signature synchronized public boolean isEmpty() { return map.isEmpty(); } @Signature synchronized public boolean has(String key) { return map.containsKey(key); } @Signature synchronized public Memory count(Environment env, Memory... args) { return LongMemory.valueOf(map.size()); } @Signature synchronized public Memory get(String key) { return get(key, Memory.UNDEFINED); } @Signature synchronized public Memory getOrCreate(String key, Invoker create) throws Throwable { Memory result = map.get(key); if (result == null) { result = create.call(); map.put(key, result); } return result; } @Signature synchronized public Memory get(String key, Memory defaultValue) { Memory result = map.get(key); return result == null ? defaultValue : result; } @Signature synchronized public Memory set(String key, Memory value, boolean override) { if (override || map.get(key) == null) { Memory result = map.put(key, value); return result == null ? Memory.UNDEFINED : result; } return Memory.NULL; } @Signature public Memory set(String key, Memory value) { return set(key, value, true); } @Signature synchronized public Memory remove(String key) { Memory memory = map.remove(key); return memory == null ? Memory.UNDEFINED : memory; } @Signature synchronized public void clear() { map.clear(); } @Signature synchronized public void __clone() { this.map = new LinkedHashMap<String, Memory>(map); } @Override synchronized public ForeachIterator getNewIterator(Environment env, boolean getReferences, boolean getKeyReferences) { final Object mutex = this; return new ForeachIterator(getReferences, getKeyReferences, false) { private Iterator<Map.Entry<String, Memory>> entries; @Override protected boolean init() { reset(); synchronized (mutex) { return !map.isEmpty(); } } @Override protected boolean nextValue() { synchronized (mutex) { if (entries.hasNext()) { Map.Entry<String, Memory> entry = entries.next(); currentKey = entry.getKey(); currentKeyMemory = StringMemory.valueOf(currentKey.toString()); currentValue = entry.getValue(); if (!getReferences) { currentValue = currentValue.toValue(); } return true; } return false; } } @Override protected boolean prevValue() { return false; } @Override public void reset() { synchronized (mutex) { entries = map.entrySet().iterator(); } } }; } @Override public ForeachIterator getNewIterator(Environment env) { return getNewIterator(env, false, false); } } }