package php.runtime.memory;
import php.runtime.Memory;
import php.runtime.common.Messages;
import php.runtime.common.collections.map.LinkedMap;
import php.runtime.env.Environment;
import php.runtime.env.TraceInfo;
import php.runtime.exceptions.RecursiveException;
import php.runtime.lang.ForeachIterator;
import php.runtime.lang.IObject;
import php.runtime.lang.StdClass;
import php.runtime.memory.helper.ArrayKeyMemory;
import php.runtime.memory.helper.ArrayValueMemory;
import php.runtime.memory.helper.ShortcutMemory;
import php.runtime.memory.support.MemoryOperation;
import php.runtime.memory.support.MemoryStringUtils;
import php.runtime.memory.support.MemoryUtils;
import php.runtime.reflection.support.ReflectionUtils;
import java.nio.charset.Charset;
import java.util.*;
public class ArrayMemory extends Memory implements Iterable<ReferenceMemory> {
protected long lastLongIndex;
protected int size;
protected int copies;
protected ArrayMemory original;
protected List<ReferenceMemory> list;
protected LinkedMap<Object, ReferenceMemory> map;
protected ForeachIterator foreachIterator;
public ArrayMemory(boolean asMap) {
super(Type.ARRAY);
if (asMap)
convertToMap();
else {
list = new ArrayList<ReferenceMemory>();
}
lastLongIndex = -1;
}
public ArrayMemory(){
this(false);
}
@Deprecated
public ArrayMemory(Collection collection){
this();
for(Object el : collection) {
if (el == null) {
add(NULL);
continue;
}
MemoryOperation operation = MemoryOperation.get(el.getClass(), null);
if (operation != null) {
add(operation.unconvertNoThow(null, null, el));
}
}
}
@Deprecated
public ArrayMemory(Object... array){
this();
for(Object el : array) {
if (el == null) {
list.add(new ReferenceMemory());
continue;
}
MemoryOperation operation = MemoryOperation.get(el.getClass(), null);
if (operation != null) {
list.add(new ReferenceMemory(operation.unconvertNoThow(null, null, el)));
}
}
size = array.length;
lastLongIndex = size - 1;
}
@Deprecated
public ArrayMemory(boolean toImmutable, Memory... array){
this();
if (array != null){
for(Memory el : array){
list.add(new ReferenceMemory(toImmutable ? el.toImmutable() : el));
}
size = array.length;
lastLongIndex = size - 1;
}
}
@Deprecated
public ArrayMemory(String[] array){
this();
for(String el : array) {
list.add(new ReferenceMemory(StringMemory.valueOf(el)));
}
size = array.length;
lastLongIndex = size - 1;
}
@Deprecated
public ArrayMemory(Map map){
this();
for(Object key : map.keySet()){
Object el = map.get(key);
put(ArrayMemory.toKey(MemoryUtils.valueOf(key)), MemoryUtils.valueOf(el));
}
}
public static Memory valueOf(){
return new ArrayMemory();
}
public static ArrayMemory valueOfRef(ArrayMemory value){
if (value == null)
return new ArrayMemory();
else
return value;
}
public Set<Object> keySet() {
if (list != null) {
Set<Object> set = new HashSet<Object>(size());
for (int i = 0; i < size(); i++) {
set.add(i);
}
return set;
}
return map.keySet();
}
public ArrayMemory duplicate(){
ArrayMemory result = new ArrayMemory();
result.lastLongIndex = lastLongIndex;
result.size = size;
if (list != null){
for(ReferenceMemory item : list){
result.list.add(item.duplicate());
}
} else {
result.list = null;
result.map = new LinkedMap<Object, ReferenceMemory>(map);
for(Map.Entry<Object, ReferenceMemory> entry : map.entrySet()){
result.map.put(entry.getKey(), entry.getValue().duplicate());
}
}
return result;
}
public ArrayMemory checkCopied(){
if (original != null || copies > 0) {
ArrayMemory dup = duplicate();
this.map = dup.map;
this.list = dup.list;
this.lastLongIndex = dup.lastLongIndex;
if (this.original == null){
this.copies--;
} else {
this.original.copies--;
this.original = null;
this.copies = 0;
}
return dup;
}
return null;
}
public static Object toKey(Memory key){
switch (key.type){
case STRING: {
String key1 = key.toString();
Memory number = StringMemory.toLong(key1);
if (number == null)
return key1;
else
return number;
}
case INT: return key;
case NULL: return Memory.CONST_EMPTY_STRING;
case REFERENCE: return toKey(key.toValue());
default:
return LongMemory.valueOf(key.toLong());
}
}
public boolean containsLongKey(long key) {
return containsKey(LongMemory.valueOf(key));
}
public boolean containsKey(Object key) {
if (size() == 0) {
return false;
}
if (list != null) {
long t = MemoryUtils.valueOf(key).toLong();
return t >= 0 && t < list.size();
}
return map.containsKey(key);
}
private void convertToMap(){
map = new LinkedMap<Object, ReferenceMemory>();
if (list != null){
int i = 0;
for(ReferenceMemory memory : list){
if (memory != null){
map.put(LongMemory.valueOf(i), memory);
}
i++;
}
}
list = null;
}
public void renameKey(Memory oldKey, Memory newKey){
checkCopied();
if (list != null)
convertToMap();
Object key1 = toKey(oldKey);
Object key2 = toKey(newKey);
map.put(key2, map.remove(key1));
}
public ReferenceMemory get(Memory key){
return getByScalar(toKey(key));
}
public ReferenceMemory getOrCreate(Memory key){
return getByScalarOrCreate(toKey(key));
}
public ReferenceMemory getOrCreateAsShortcut(Memory key){
return getByScalarOrCreateAsShortcut(toKey(key));
}
public ReferenceMemory getByScalarOrCreate(Object sKey, Memory initValue){
ReferenceMemory value = getByScalar(sKey);
if (value == null)
return put(sKey, initValue);
return value;
}
public ReferenceMemory getByScalarOrCreateAsShortcut(Object sKey){
//checkCopied();
ReferenceMemory value = getByScalar(sKey);
if (value == null) {
value = new ReferenceMemory(UNDEFINED);
return put(sKey, new ShortcutMemory(value));
}
if (value instanceof ShortcutMemory)
return (ShortcutMemory)value.value;
else {
put(sKey, new ShortcutMemory(value));
return value;
}
}
public ReferenceMemory getByScalarOrCreate(Object sKey){
return getByScalarOrCreate(sKey, UNDEFINED);
}
public ReferenceMemory getByScalar(Object key){
if (list != null){
if (key instanceof Memory){
int index = (int)((Memory) key).toLong();
if (index >= 0 && index < list.size()){
return list.get(index);
} else
return null;
} else
return null;
} else {
return map.get(key);
}
}
public void add(IObject object) {
add(new ObjectMemory(object));
}
public void add(long value) {
add(LongMemory.valueOf(value));
}
public void add(String value) {
add(StringMemory.valueOf(value));
}
public void add(double value) {
add(new DoubleMemory(value));
}
public void add(boolean value) {
add(value ? TRUE : FALSE);
}
public void addNull() {
add(NULL);
}
public ReferenceMemory add(Memory value){
if (value instanceof KeyValueMemory){
KeyValueMemory keyValue = (KeyValueMemory)value;
return put(toKey(keyValue.key), keyValue.value.toImmutable());
}
ReferenceMemory ref;
if (list != null){
lastLongIndex++;
ref = new ReferenceMemory(value);
list.add(ref);
size++;
} else {
ref = put(LongMemory.valueOf(++lastLongIndex), value);
}
return ref;
}
/**
* @param array
* @param recursive
*/
public void merge(ArrayMemory array, boolean recursive, Set<Integer> done){
checkCopied();
if (recursive && done == null)
done = new HashSet<Integer>();
if (list != null && array.list != null){
for(ReferenceMemory reference : array.list)
list.add(new ReferenceMemory(reference.toImmutable()));
size = list.size();
lastLongIndex = size - 1;
} else {
if (list != null)
convertToMap();
if (array.list != null){
for(ReferenceMemory reference : array.list){
add(reference.toImmutable());
}
} else {
for(Map.Entry<Object, ReferenceMemory> entry : array.map.entrySet()){
Object key = entry.getKey();
if (key instanceof LongMemory){
add(entry.getValue().toImmutable());
} else {
Memory value = entry.getValue();
if (recursive && value.isArray()) {
if (done.contains(value.getPointer()))
throw new RecursiveException();
Memory current = getByScalar(key).toImmutable();
if (current.isArray()) {
value = value.toImmutable();
int pointer = value.getPointer();
done.add(pointer); // for check recursive
ArrayMemory result = (ArrayMemory)value; // already array immutable above
result.merge((ArrayMemory)current, recursive, done);
put(key, result);
done.remove(pointer);
} else
put(key, value.toImmutable());
} else {
put(key, value.toImmutable());
}
}
}
}
}
}
public void putAll(ArrayMemory array){
if (array.list != null){
int i = 0;
for(ReferenceMemory memory : array.list){
if (memory != null)
put(LongMemory.valueOf(i), memory.toImmutable());
i++;
}
} else {
if (list != null)
convertToMap();
if (array.lastLongIndex > lastLongIndex)
lastLongIndex = array.lastLongIndex;
for(Map.Entry<Object, ReferenceMemory> entry : array.map.entrySet()){
put(entry.getKey(), entry.getValue().toImmutable());
}
}
}
public void putAllRef(ArrayMemory array){
if (array.list != null){
int i = 0;
for(ReferenceMemory memory : array.list){
if (memory != null)
put(LongMemory.valueOf(i), memory);
i++;
}
} else {
if (list != null)
convertToMap();
if (array.lastLongIndex > lastLongIndex)
lastLongIndex = array.lastLongIndex;
map.putAll(array.map);
}
}
public ReferenceMemory putAsKeyString(String key, Memory value){
ReferenceMemory mem = new ReferenceMemory(value);
if (list != null)
convertToMap();
Memory last = map.put(key, mem);
if (last == null){
size++;
}
return mem;
}
public ReferenceMemory put(Object key, Memory value) {
ReferenceMemory mem = new ReferenceMemory(value);
if (key instanceof LongMemory){
int index = (int)((LongMemory)key).value;
if (index > lastLongIndex)
lastLongIndex = index;
if (list != null){
int size = list.size();
if (index >= 0){
if (index < size){
list.set(index, mem);
//this.size++;
return mem;
} else if (index == size){
list.add(mem);
this.size++;
return mem;
} else {
convertToMap();
}
} else
convertToMap();
}
} else {
if (!(key instanceof String))
key = key.toString();
if (list != null)
convertToMap();
}
Memory last = map.put(key, mem);
if (last == null){
size++;
}
return mem;
}
public Memory removeByScalar(Object key){
if (list != null){
int index = -1;
if (key instanceof Long)
index = ((Long) key).intValue();
else if (key instanceof Integer)
index = ((Integer) key);
else if (key instanceof String){
Memory tmp = StringMemory.toLong((String)key);
if (tmp != null)
index = (int) tmp.toLong();
}
if (index < 0 || index >= list.size())
return null;
if (index == size - 1) {
size--;
lastLongIndex = size - 1;
return list.remove(index);
} else {
key = (long)index;
convertToMap();
}
}
{
if (key instanceof Long)
key = LongMemory.valueOf((Long)key);
else if (key instanceof Integer)
key = LongMemory.valueOf((Integer)key);
else if (key instanceof String){
Memory tmp = StringMemory.toLong((String)key);
if (tmp != null)
key = tmp;
}
Memory memory = map.remove(key);
if (memory != null)
size--;
return memory;
}
}
public Memory remove(Memory key){
Object _key = toKey(key);
if (list != null){
int index = _key instanceof LongMemory ? (int) key.toLong() : -1;
if (index < 0 || index >= list.size())
return null;
if (index == size - 1){
size--;
lastLongIndex = index - 1;
return list.remove(index);
}
//key = LongMemory.valueOf(index);
convertToMap();
}
{
Memory memory = map.remove(_key);
if (memory != null)
size--;
return memory;
}
}
public int size(){
return size;
}
public void unshift(Memory value, int count){
checkCopied();
if (size == 0) {
for(int i = 0; i < count; i++)
add(value);
} else {
if (list != null) {
List<ReferenceMemory> tmp = new ArrayList<ReferenceMemory>();
for(int i = 0; i < count; i++)
tmp.add(new ReferenceMemory(value));
list.addAll(0, tmp);
size = list.size();
} else {
ArrayMemory tmp = new ArrayMemory();
tmp.convertToMap();
for(int i = 0; i < count; i++)
tmp.add(value);
ForeachIterator iterator = getNewIterator(null, false, false);
while (iterator.next()){
Object key = iterator.getKey();
if (key instanceof String)
tmp.put(key, iterator.getValue());
else
add(iterator.getValue());
}
lastLongIndex = tmp.lastLongIndex;
map = tmp.map;
size = tmp.size;
}
}
}
public void unshift(Memory... values){
checkCopied();
if (values == null) {
throw new NullPointerException();
}
if (size == 0) {
for (Memory value : values)
add(value);
} else {
if (list != null) {
if (values.length > 1) {
List<ReferenceMemory> tmp = new ArrayList<ReferenceMemory>();
for (Memory value : values)
tmp.add(new ReferenceMemory(value));
list.addAll(0, tmp);
size = list.size();
} else if (values.length == 1) {
list.add(0, new ReferenceMemory(values[0]));
size = list.size();
}
} else {
ArrayMemory tmp = new ArrayMemory();
tmp.convertToMap();
for(Memory el : values)
tmp.add(el);
ForeachIterator iterator = getNewIterator(null, false, false);
while (iterator.next()){
Object key = iterator.getKey();
if (key instanceof String)
tmp.put(key, iterator.getValue());
else
add(iterator.getValue());
}
lastLongIndex = tmp.lastLongIndex;
map = tmp.map;
size = tmp.size;
}
}
}
public Memory shift(){
checkCopied();
if (size < 1)
return null;
size -= 1;
Memory value;
if (list != null){
value = list.get(0);
list.remove(0);
} else {
value = map.remove(map.firstKey());
}
return value.toValue();
}
public Memory pop(){
checkCopied();
if (size < 1)
return null;
Memory value;
if (list != null){
value = list.get(size - 1);
list.remove(size - 1);
} else {
value = map.remove(map.lastKey());
}
size -= 1;
return value.toValue();
}
public Memory peek(){
if (size < 1)
return null;
Memory value;
if (list != null)
value = list.get(size - 1);
else {
value = map.get(map.lastKey());
}
return value.toValue();
}
public Memory peekKey() {
if (size < 1)
return null;
Memory value;
if (list != null)
return LongMemory.valueOf(size - 1);
else {
Object key = map.lastKey();
if (key instanceof Memory) {
return (Memory) key;
} else if (key instanceof String) {
return StringMemory.valueOf(key.toString());
}
}
return null;
}
public Memory getRandomElementKey(Random rnd){
int index = rnd.nextInt(size);
if (list != null){
return LongMemory.valueOf(index);
} else {
Iterator<Object> keys = map.keySet().iterator();
for(int i = 0; i < index; i++){
keys.next();
}
Object key = keys.next();
if (key instanceof LongMemory)
return (LongMemory)key;
else
return new StringMemory((String)key);
}
}
public void shuffle(Random rnd){
checkCopied();
if (list != null){
Collections.shuffle(list, rnd);
} else {
Set<Object> keys = map.keySet();
List<ReferenceMemory> values = new ArrayList<ReferenceMemory>(map.values());
Collections.shuffle(values, rnd);
int i = 0;
for(Object key : keys){
map.put(key, values.get(i));
i++;
}
}
}
public void clear(){
if (list != null){
list = new ArrayList<ReferenceMemory>();
}
if (map != null){
map = new LinkedMap<Object, ReferenceMemory>();
}
size = 0;
}
public int compare(ArrayMemory otherRef, boolean strict) {
return compare(otherRef, strict, null);
}
public int compare(ArrayMemory otherRef, boolean strict, Set<Integer> used) {
int size1 = size(),
size2 = otherRef.size();
if (size1 < size2)
return -1;
else if (size1 > size2)
return 1;
ForeachIterator iterator = this.foreachIterator(false, false);
ForeachIterator iterator2 = null;
if (strict)
iterator2 = otherRef.foreachIterator(false, false);
if (used == null)
used = new HashSet<Integer>();
while (iterator.next()){
Memory value1 = iterator.getValue();
Memory key = iterator.getMemoryKey();
Memory value2;
if (iterator2 == null)
value2 = otherRef.get(key);
else {
if (!iterator2.next())
return -2;
Object key2 = iterator2.getKey();
if (!iterator.getKey().equals(key2))
return -2;
value2 = iterator2.getValue();
}
if (value2 == null)
return -2;
if (value1.isArray() && value2.isArray()){
ArrayMemory arr1 = value1.toValue(ArrayMemory.class);
if (used.add(value2.getPointer())){
int r = arr1.compare(value2.toValue(ArrayMemory.class), strict, used);
if (r == 0) {
used.remove(value2.getPointer());
continue;
}
return r;
}
used.remove(value2.getPointer());
} else if (value1.isObject() && value2.isObject()){
ObjectMemory o1 = value1.toValue(ObjectMemory.class);
ObjectMemory o2 = value2.toValue(ObjectMemory.class);
return o1.compare(o2.value, strict, used);
} else {
if ((strict && value1.identical(value2)) || (!strict && value1.equal(value2)))
continue;
if (value1.smaller(value2))
return -1;
else
return 1;
}
}
return 0;
}
@Override
public Memory toImmutable() {
if (copies >= 0){
ArrayMemory mem = new ArrayMemory();
mem.list = list;
mem.original = this;
mem.size = size;
mem.list = list;
mem.map = map;
mem.lastLongIndex = lastLongIndex;
copies++;
reset();
return mem;
} else {
copies++;
return this;
}
}
public ArrayMemory toConstant(){
if (copies == 0)
copies--;
else
throw new RuntimeException("Cannot convert array to a constant value with copies != 0");
return this;
}
public Memory[] values(boolean asImmutable){
Memory[] result = new Memory[size];
int i = 0;
for(ReferenceMemory el : this){
result[i++] = asImmutable ? el.toImmutable() : el.toValue();
}
return result;
}
public Memory[] values(){
return values(false);
}
@Override
public long toLong() {
return size == 0 ? 0 : 1;
}
@Override
public double toDouble() {
return size == 0 ? 0 : 1;
}
@Override
public boolean toBoolean() {
return size != 0;
}
@Override
public Memory toNumeric() {
return size == 0 ? CONST_INT_0 : CONST_INT_1;
}
@Override
public String toString() {
return "Array";
}
@Override
public Memory inc() {
return toNumeric().inc();
}
@Override
public Memory dec() {
return toNumeric().dec();
}
@Override
public Memory negative() {
return toNumeric().negative();
}
@Override
public Memory plus(Memory memory) {
switch (memory.type){
case ARRAY:
ArrayMemory left = (ArrayMemory)toImmutable();
ArrayMemory other = (ArrayMemory)memory;
ForeachIterator iterator = other.foreachIterator(false, false);
while (iterator.next()){
Object key = iterator.getKey();
Memory origin = getByScalar(key);
if (origin == null){
left.checkCopied();
left.put(key, iterator.getValue().toImmutable());
}
}
return left;
case REFERENCE: return plus(memory.toValue());
default:
return toNumeric().plus(memory);
}
}
@Override
public Memory minus(Memory memory) {
return toNumeric().minus(memory);
}
@Override
public Memory mul(Memory memory) {
return toNumeric().mul(memory);
}
@Override
public Memory pow(Memory memory) {
return toNumeric().pow(memory);
}
@Override
public Memory div(Memory memory) {
return toNumeric().div(memory);
}
@Override
public boolean equal(Memory memory) {
switch (memory.type){
case ARRAY:
return compare((ArrayMemory)memory, false) == 0;
case REFERENCE: return equal(memory.toValue());
default:
return false;
}
}
@Override
public boolean notEqual(Memory memory) {
return !equal(memory);
}
@Override
public boolean smaller(Memory memory) {
switch (memory.type){
case ARRAY:
return compare((ArrayMemory)memory, false) == -1;
case REFERENCE: return equal(memory.toValue());
default:
return false;
}
}
@Override
public boolean smallerEq(Memory memory) {
switch (memory.type){
case ARRAY:
int r = compare((ArrayMemory)memory, false);
return r == 0 || r == -1;
case REFERENCE: return equal(memory.toValue());
default:
return false;
}
}
@Override
public boolean greater(Memory memory) {
switch (memory.type){
case ARRAY:
return compare((ArrayMemory)memory, false) == 1;
case REFERENCE: return equal(memory.toValue());
default:
return false;
}
}
@Override
public boolean greaterEq(Memory memory) {
switch (memory.type){
case ARRAY:
int r = compare((ArrayMemory)memory, false);
return r == 0 || r == 1;
case REFERENCE: return equal(memory.toValue());
default:
return false;
}
}
@Override
public int hashCode() {
return toString().hashCode();
}
@Override
public void unset() {
if (original != null){
original.copies--;
original = null;
} else
copies--;
if (list != null){
for(ReferenceMemory memory : list)
if (memory.type == type)
memory.unset();
}
if (map != null){
for(ReferenceMemory memory : map.values())
if (memory.type == type)
memory.unset();
}
clear();
}
@Override
public Memory valueOfIndex(TraceInfo trace, Memory index) {
switch (index.getRealType()){
case OBJECT:
case ARRAY: return UNDEFINED; // TODO ADD WARNING
}
Memory e = get(index);
return e == null ? UNDEFINED : e;
}
@Override
public Memory valueOfIndex(TraceInfo trace, long index) {
Memory e = getByScalar(LongMemory.valueOf(index));
return e == null ? UNDEFINED : e;
}
@Override
public Memory valueOfIndex(TraceInfo trace, double index) {
Memory e = getByScalar(LongMemory.valueOf((long) index));
return e == null ? UNDEFINED : e;
}
@Override
public Memory valueOfIndex(TraceInfo trace, boolean index) {
Memory e = getByScalar(index ? CONST_INT_0 : CONST_INT_1);
return e == null ? UNDEFINED : e;
}
@Override
public Memory valueOfIndex(TraceInfo trace, String index) {
Memory number = StringMemory.toLong(index);
Memory e = number == null ? getByScalar(index) : getByScalar(number);
return e == null ? UNDEFINED : e;
}
@Override
public void unsetOfIndex(TraceInfo trace, Memory index) {
checkCopied();
remove(index);
}
@Override
public Memory issetOfIndex(TraceInfo trace, Memory index) {
Memory value = get(index);
return value == null ? NULL : value;
}
@Override
public Memory refOfPush(TraceInfo trace){
checkCopied();
return add(UNDEFINED);
}
@Override
public Memory refOfIndexAsShortcut(TraceInfo trace, Memory index) {
switch (index.getRealType()){
case OBJECT:
case ARRAY: return new ReferenceMemory(); // TODO ADD WARNING
}
checkCopied();
return getOrCreateAsShortcut(index);
}
@Override
public Memory refOfIndex(TraceInfo trace, Memory index) {
switch (index.getRealType()){
case OBJECT:
case ARRAY: return new ReferenceMemory(); // TODO ADD WARNING
}
checkCopied();
return getOrCreate(index);
}
@Override
public Memory refOfIndex(TraceInfo trace, long index) {
checkCopied();
return getOrCreate(LongMemory.valueOf(index));
}
@Override
public Memory refOfIndex(TraceInfo trace, double index) {
return refOfIndex(null, LongMemory.valueOf((long) index));
}
@Override
public Memory refOfIndex(TraceInfo trace, boolean index) {
checkCopied();
return getOrCreate(index ? CONST_INT_1 : CONST_INT_0);
}
@Override
public Memory refOfIndex(TraceInfo trace, String index) {
checkCopied();
Memory number = StringMemory.toLong(index);
return number == null ? getByScalarOrCreate(index) : getByScalarOrCreate(number);
}
@Override
public boolean identical(Memory memory) {
switch (memory.type){
case ARRAY:
return compare((ArrayMemory)memory, true) == 0;
case REFERENCE: return equal(memory.toValue());
default:
return false;
}
}
@Override
public boolean identical(long value) {
return false;
}
@Override
public boolean identical(double value) {
return false;
}
@Override
public boolean identical(boolean value) {
return false;
}
@Override
public boolean identical(String value) {
return false;
}
@Override
public Iterator<ReferenceMemory> iterator() {
if (list != null) {
return list.iterator();
} else
return map.values().iterator();
}
public ForeachIterator foreachIterator(boolean getReferences, boolean withPrevious) {
return foreachIterator(getReferences, false, withPrevious, true);
}
public ForeachIterator foreachIterator(boolean getReferences, boolean getKeyReferences, boolean withPrevious) {
return foreachIterator(getReferences, getKeyReferences, withPrevious, true);
}
public ForeachIterator foreachIterator(boolean getReferences, boolean getKeyReferences, boolean withPrevious, final boolean freeze) {
return new ForeachIterator(getReferences, getKeyReferences, withPrevious){
protected int cursor = 0;
protected int listMax;
protected Iterator<Object> keys;
@Override
public void reset() {
if (getKeyReferences && list != null)
ArrayMemory.this.convertToMap();
if (list == null) {
if (withPrevious || getKeyReferences)
keys = new ArrayList<Object>(map.keySet()).listIterator();
else {
if (freeze) {
keys = new ArrayList<Object>(map.keySet()).iterator();
} else {
keys = map.keySet().iterator();
}
}
} else {
listMax = list.size();
}
}
@Override
protected boolean init() {
if (getKeyReferences && list != null)
ArrayMemory.this.convertToMap();
if (list == null) {
if (withPrevious || getKeyReferences) {
keys = new ArrayList<Object>(map.keySet()).listIterator();
} else {
keys = new ArrayList<Object>(map.keySet()).iterator();
}
} else {
listMax = list.size();
}
return true;
}
private void setCurrentValue(ReferenceMemory value){
if (getReferences) {
if (plainReferences)
currentValue = value;
else
currentValue = new ArrayValueMemory(getMemoryKey(), ArrayMemory.this, value);
} else
currentValue = value.value;
if (getKeyReferences) {
currentKeyMemory = new ArrayKeyMemory(ArrayMemory.this, getMemoryKey());
}
}
@Override
public boolean end() {
if (ArrayMemory.this.size == 0)
return false;
if (ArrayMemory.this.list != null){
cursor = ArrayMemory.this.size - 1;
currentKey = (long)cursor;
setCurrentValue(list.get(cursor));
return true;
} else {
init = true;
ArrayList<Object> tmp = new ArrayList<Object>(map.keySet());
keys = tmp.listIterator(tmp.size() - 1);
if (keys.hasNext() && next()) {
return true;
} else {
return false;
}
}
}
@Override
protected boolean prevValue() {
if (ArrayMemory.this.list != null) {
if (cursor <= 0){
currentKey = null;
currentValue = null;
cursor--;
keys = null;
return false;
} else {
cursor--;
currentKey = LongMemory.valueOf((long)cursor);
setCurrentValue(list.get(cursor));
return true;
}
} else {
ListIterator<Object> keyIterator = (ListIterator) keys;
if (keyIterator.hasPrevious()) {
currentKey = keyIterator.previous();
setCurrentValue(map.get(currentKey));
return true;
} else {
currentKey = null;
currentValue = null;
keys = null;
cursor = -1;
return false;
}
}
}
@Override
protected boolean nextValue() {
if (withPrevious && (keys == null && cursor < 0))
return false;
if (ArrayMemory.this.list != null) {
if (((cursor >= listMax && freeze) || (cursor >= size && !freeze)) || size < listMax) {
currentKey = null;
currentValue = null;
return false;
}
currentKey = LongMemory.valueOf((long)cursor);
setCurrentValue(list.get(cursor));
cursor++;
return true;
} else {
if (keys == null) {
ArrayList<Object> tmp = new ArrayList<Object>(map.keySet());
keys = tmp.listIterator(cursor - 1);
}
if (keys.hasNext()) {
currentKey = keys.next();
setCurrentValue(map.get(currentKey));
return true;
} else {
currentKey = null;
currentValue = null;
return false;
}
}
}
};
}
@Override
public ForeachIterator getNewIterator(Environment env, boolean getReferences, boolean getKeyReferences) {
return foreachIterator(getReferences, getKeyReferences, false);
}
public ForeachIterator getCurrentIterator() {
if (foreachIterator == null) {
foreachIterator = foreachIterator(false, true);
}
return foreachIterator;
}
protected void reset() {
foreachIterator = null;
}
public Memory resetCurrentIterator(){
reset();
ForeachIterator iterator = getCurrentIterator();
if (size == 0)
return FALSE;
else {
iterator.next();
Memory tmp = iterator.getValue();
iterator.prev();
return tmp;
}
}
@Override
public byte[] getBinaryBytes(Charset charset) {
return MemoryStringUtils.getBinaryBytes(this);
}
public boolean isList(){
return list != null;
}
@Override
public Memory toArray() {
return this;
}
@Override
public Memory toObject(Environment env) {
StdClass stdClass = new StdClass(env);
ArrayMemory props = stdClass.getProperties();
ForeachIterator iterator = getNewIterator(env, false, false);
while (iterator.next()){
props.refOfIndex(null, iterator.getMemoryKey()).assign(iterator.getValue());
}
return new ObjectMemory(stdClass);
}
public int[] toIntArray() {
int[] r = new int[size];
int i = 0;
for (Memory e : this) {
r[i] = e.toInteger();
i++;
}
return r;
}
public long[] toLongArray() {
long[] r = new long[size];
int i = 0;
for (Memory e : this) {
r[i] = e.toLong();
i++;
}
return r;
}
public String[] toStringArray() {
String[] r = new String[size];
int i = 0;
for (Memory e : this) {
r[i] = e.toString();
i++;
}
return r;
}
public float[] toFloatArray() {
float[] r = new float[size];
int i = 0;
for (Memory e : this) {
r[i] = e.toFloat();
i++;
}
return r;
}
public double[] toDoubleArray() {
double[] r = new double[size];
int i = 0;
for (Memory e : this) {
r[i] = e.toDouble();
i++;
}
return r;
}
public boolean[] toBoolArray() {
boolean[] r = new boolean[size];
int i = 0;
for (Memory e : this) {
r[i] = e.toBoolean();
i++;
}
return r;
}
@SuppressWarnings("unchecked")
public <T extends IObject> List<T> toObjectArray(Class<T> clazz) {
List<T> r = new ArrayList<T>();
int i = 0;
for(Memory e : this) {
if (e.instanceOf(clazz))
r.add(e.toObject(clazz));
else {
throw new IllegalArgumentException(Messages.ERR_INVALID_ARRAY_ELEMENT_TYPE.fetch(
ReflectionUtils.getClassName(clazz), ReflectionUtils.getGivenName(e)
));
}
}
return r;
}
public Map<String, String> toStringMap() {
Map<String, String> r = new LinkedHashMap<String, String>();
ForeachIterator iterator = foreachIterator(false, false);
while (iterator.next()) {
r.put(iterator.getKey().toString(), iterator.getValue().toString());
}
return r;
}
public Map<String, Integer> toIntMap() {
Map<String, Integer> r = new LinkedHashMap<String, Integer>();
ForeachIterator iterator = foreachIterator(false, false);
while (iterator.next()) {
r.put(iterator.getKey().toString(), iterator.getValue().toInteger());
}
return r;
}
public Map<String, Long> toLongMap() {
Map<String, Long> r = new LinkedHashMap<String, Long>();
ForeachIterator iterator = foreachIterator(false, false);
while (iterator.next()) {
r.put(iterator.getKey().toString(), iterator.getValue().toLong());
}
return r;
}
public Map<String, Double> toDoubleMap() {
Map<String, Double> r = new LinkedHashMap<String, Double>();
ForeachIterator iterator = foreachIterator(false, false);
while (iterator.next()) {
r.put(iterator.getKey().toString(), iterator.getValue().toDouble());
}
return r;
}
public Map<String, Boolean> toBooleanMap() {
Map<String, Boolean> r = new LinkedHashMap<String, Boolean>();
ForeachIterator iterator = foreachIterator(false, false);
while (iterator.next()) {
r.put(iterator.getKey().toString(), iterator.getValue().toBoolean());
}
return r;
}
public <T extends IObject> Map<String, T> toObjectMap(Class<T> clazz) {
Map<String, T> r = new LinkedHashMap<String, T>();
ForeachIterator iterator = foreachIterator(false, false);
while (iterator.next()) {
Memory e = iterator.getValue();
if (e.instanceOf(clazz))
r.put(iterator.getKey().toString(), e.toObject(clazz));
else {
throw new IllegalArgumentException(Messages.ERR_INVALID_ARRAY_ELEMENT_TYPE.fetch(
ReflectionUtils.getClassName(clazz), ReflectionUtils.getGivenName(e)
));
}
}
return r;
}
public static ArrayMemory ofPair(String key, Memory value) {
ArrayMemory r = new ArrayMemory();
r.refOfIndex(key).assign(value.toImmutable());
return r;
}
public static ArrayMemory ofPair(String key, String value) {
return ofPair(key, StringMemory.valueOf(value));
}
public static ArrayMemory ofPair(String key, long value) {
return ofPair(key, LongMemory.valueOf(value));
}
public static ArrayMemory ofPair(String key, double value) {
return ofPair(key, DoubleMemory.valueOf(value));
}
public static ArrayMemory ofPair(String key, boolean value) {
return ofPair(key, TrueMemory.valueOf(value));
}
public static ArrayMemory ofPair(String key, IObject value) {
return ofPair(key, ObjectMemory.valueOf(value));
}
public static ArrayMemory ofShorts(short... array) {
ArrayMemory result = new ArrayMemory();
if (array != null) {
for (int el : array) result.add(el);
}
return result;
}
public static ArrayMemory ofIntegers(int... array) {
ArrayMemory result = new ArrayMemory();
if (array != null) {
for (int el : array) result.add(el);
}
return result;
}
public static ArrayMemory ofBytes(byte... array) {
ArrayMemory result = new ArrayMemory();
if (array != null) {
for (int el : array) result.add(el);
}
return result;
}
public static ArrayMemory ofLongs(long... array) {
ArrayMemory result = new ArrayMemory();
if (array != null) {
for (long el : array) result.add(el);
}
return result;
}
public static ArrayMemory ofFloats(float... array) {
ArrayMemory result = new ArrayMemory();
if (array != null) {
for (float el : array) result.add(el);
}
return result;
}
public static ArrayMemory ofDoubles(double... array) {
ArrayMemory result = new ArrayMemory();
if (array != null) {
for (double el : array) result.add(el);
}
return result;
}
public static ArrayMemory ofBooleans(boolean... array) {
ArrayMemory result = new ArrayMemory();
if (array != null) {
for (boolean el : array) result.add(el);
}
return result;
}
public static ArrayMemory ofChars(char... array) {
ArrayMemory result = new ArrayMemory();
if (array != null) {
for (char el : array) result.add(StringMemory.valueOf(el));
}
return result;
}
public static ArrayMemory ofStrings(String... array) {
ArrayMemory result = new ArrayMemory();
if (array != null) {
for (String el : array) result.add(el);
}
return result;
}
public static ArrayMemory ofStringCollection(Collection<String> list) {
ArrayMemory result = new ArrayMemory();
for (String el : list) result.add(el);
return result;
}
public static ArrayMemory ofObjects(IObject... array) {
ArrayMemory result = new ArrayMemory();
if (array != null) {
for (IObject el : array) result.add(el);
}
return result;
}
public static ArrayMemory of(Memory... array) {
ArrayMemory result = new ArrayMemory();
if (array != null){
for(Memory el : array) {
result.add(el.toImmutable());
}
}
return result;
}
public static ArrayMemory ofCollection(Collection<Memory> list) {
ArrayMemory result = new ArrayMemory();
for(Memory el : list) {
result.add(el.toImmutable());
}
return result;
}
public static ArrayMemory ofMap(Map<String, Memory> map) {
ArrayMemory result = new ArrayMemory();
for (Map.Entry<String, Memory> entry : map.entrySet()) {
result.putAsKeyString(entry.getKey(), entry.getValue().toImmutable());
}
return result;
}
public static ArrayMemory ofStringMap(Map<String, String> map) {
ArrayMemory result = new ArrayMemory();
for (Map.Entry<String, String> entry : map.entrySet()) {
result.putAsKeyString(entry.getKey(), StringMemory.valueOf(entry.getValue()));
}
return result;
}
public ArrayMemory slice(int offset) {
return slice(offset, false);
}
public ArrayMemory slice(int offset, int length) {
return slice(offset, length, false);
}
public ArrayMemory slice(int offset, boolean saveKeys) {
ArrayMemory result = new ArrayMemory();
if (offset < 0) {
offset = size() + offset;
}
if (isList()) {
int i = 0;
try {
for (ReferenceMemory referenceMemory : list.subList(offset, list.size())) {
if (saveKeys) {
result.refOfIndex(i + offset).assign(referenceMemory.toImmutable());
} else {
result.add(referenceMemory.toImmutable());
}
i++;
}
} catch (IllegalArgumentException e) {
throw new IndexOutOfBoundsException(e.getMessage());
}
} else {
int i = 0;
ForeachIterator iterator = foreachIterator(false, false);
while (iterator.next()) {
if (i >= offset) {
if (saveKeys || !iterator.isLongKey()) {
result.put(iterator.getKey(), iterator.getValue().toImmutable());
} else {
result.add(iterator.getValue().toImmutable());
}
}
i++;
}
}
return result;
}
public ArrayMemory slice(int offset, int length, boolean saveKeys) {
ArrayMemory result = new ArrayMemory();
if (offset < 0) {
offset = size() + offset;
}
if (length < 0) {
length = size() + length - offset;
}
if (isList()) {
int i = 0;
try {
for (ReferenceMemory referenceMemory : list.subList(offset, offset + length)) {
if (saveKeys) {
result.refOfIndex(i + offset).assign(referenceMemory.toImmutable());
} else {
result.add(referenceMemory.toImmutable());
}
i++;
}
} catch (IllegalArgumentException e) {
throw new IndexOutOfBoundsException(e.getMessage());
}
} else {
int i = 0, count = 0;
ForeachIterator iterator = foreachIterator(false, false);
while (iterator.next()) {
if (i >= offset) {
count++;
if (saveKeys || !iterator.isLongKey()) {
result.put(iterator.getKey(), iterator.getValue().toImmutable());
} else {
result.add(iterator.getValue().toImmutable());
}
if (count >= length) {
break;
}
}
i++;
}
}
return result;
}
}