package org.develnext.jphp.zend.ext.standard;
import org.develnext.jphp.zend.ext.support.NaturalOrderComparator;
import php.runtime.Memory;
import php.runtime.annotation.Runtime;
import php.runtime.annotation.Runtime.Reference;
import php.runtime.common.Callback;
import php.runtime.env.Environment;
import php.runtime.env.TraceInfo;
import php.runtime.exceptions.RecursiveException;
import php.runtime.ext.core.MathFunctions;
import php.runtime.ext.support.compile.FunctionsContainer;
import php.runtime.invoke.Invoker;
import php.runtime.lang.ForeachIterator;
import php.runtime.memory.ArrayMemory;
import php.runtime.memory.KeyValueMemory;
import php.runtime.memory.LongMemory;
import php.runtime.memory.ReferenceMemory;
import java.util.*;
import static org.develnext.jphp.zend.ext.standard.ArrayConstants.*;
import static php.runtime.Memory.Type.ARRAY;
public class ArrayFunctions extends FunctionsContainer {
@Runtime.Immutable(ignoreRefs = true)
public static boolean in_array(Environment env, TraceInfo trace, Memory needle, @Reference Memory array,
boolean strict) {
if (expecting(env, trace, 2, array, ARRAY)) {
ForeachIterator iterator = array.getNewIterator(env, false, false);
while (iterator.next()) {
if (strict) {
if (needle.identical(iterator.getValue()))
return true;
} else {
if (needle.equal(iterator.getValue()))
return true;
}
}
return false;
} else
return false;
}
@Runtime.Immutable(ignoreRefs = true)
public static boolean in_array(Environment env, TraceInfo trace, Memory needle, @Reference Memory array) {
return in_array(env, trace, needle, array, false);
}
@Runtime.Immutable(ignoreRefs = true)
public static boolean array_key_exists(Environment env, TraceInfo trace, Memory key, @Reference Memory array) {
if (expecting(env, trace, 2, array, ARRAY)) {
ArrayMemory tmp = array.toValue(ArrayMemory.class);
return tmp.get(key) != null;
} else
return false;
}
@Runtime.Immutable(ignoreRefs = true)
public static boolean key_exists(Environment env, TraceInfo trace, Memory key, @Reference Memory array) {
return array_key_exists(env, trace, key, array);
}
public static Memory reset(Environment env, TraceInfo trace, @Reference Memory array) {
if (expectingReference(env, trace, array, "reset")) {
if (expecting(env, trace, 1, array, ARRAY)) {
ArrayMemory memory = array.toValue(ArrayMemory.class);
return memory.resetCurrentIterator().toImmutable();
}
}
return Memory.FALSE;
}
public static Memory next(Environment env, TraceInfo trace, @Reference Memory array) {
if (expectingReference(env, trace, array, "next")) {
if (expecting(env, trace, 1, array, ARRAY)) {
ArrayMemory memory = array.toValue(ArrayMemory.class);
ForeachIterator iterator = memory.getCurrentIterator();
if (iterator.next())
return iterator.getValue().toImmutable();
else
return Memory.FALSE;
}
}
return Memory.FALSE;
}
public static Memory prev(Environment env, TraceInfo trace, @Reference Memory array) {
if (expectingReference(env, trace, array, "prev")) {
if (expecting(env, trace, 1, array, ARRAY)) {
ArrayMemory memory = array.toValue(ArrayMemory.class);
ForeachIterator iterator = memory.getCurrentIterator();
if (iterator.prev())
return iterator.getValue().toImmutable();
else
return Memory.FALSE;
}
}
return Memory.FALSE;
}
public static Memory current(Environment env, TraceInfo trace, @Reference Memory array) {
if (expectingReference(env, trace, array, "current")) {
if (expecting(env, trace, 1, array, ARRAY)) {
Memory value = array.toValue(ArrayMemory.class).getCurrentIterator().getValue();
return value == null ? Memory.FALSE : value.toImmutable();
}
}
return Memory.FALSE;
}
public static Memory key(Environment env, TraceInfo trace, @Reference Memory array) {
if (expectingReference(env, trace, array, "key")) {
if (expecting(env, trace, 1, array, ARRAY)) {
Memory value = array.toValue(ArrayMemory.class).getCurrentIterator().getMemoryKey();
return value == null ? Memory.FALSE : value;
}
}
return Memory.FALSE;
}
public static Memory pos(Environment env, TraceInfo trace, @Reference Memory array) {
return current(env, trace, array);
}
public static Memory end(Environment env, TraceInfo trace, @Reference Memory array) {
if (expectingReference(env, trace, array, "end")) {
if (expecting(env, trace, 1, array, ARRAY)) {
ForeachIterator iterator = array.toValue(ArrayMemory.class).getCurrentIterator();
if (iterator.end()) {
return iterator.getValue().toImmutable();
} else {
return Memory.FALSE;
}
}
}
return Memory.FALSE;
}
public static Memory each(Environment env, TraceInfo trace, @Reference Memory array) {
if (expectingReference(env, trace, array, "each")) {
if (expecting(env, trace, 1, array, ARRAY)) {
ForeachIterator iterator = array.toValue(ArrayMemory.class).getCurrentIterator();
if (iterator.next()) {
Memory value = iterator.getValue().toImmutable();
Memory key = iterator.getMemoryKey();
ArrayMemory result = new ArrayMemory();
result.refOfIndex(1).assign(value);
result.refOfIndex("value").assign(value);
result.refOfIndex(0).assign(key);
result.refOfIndex("key").assign(key);
return result.toConstant();
} else {
return Memory.FALSE;
}
}
}
return Memory.FALSE;
}
private static Memory _array_merge(Environment env, TraceInfo trace, boolean recursive, Memory array, Memory... arrays) {
if (!array.isArray()) {
env.warning(trace, "Argument %s is not an array", 1);
return Memory.NULL;
}
if (arrays == null || arrays.length == 0)
return array;
ArrayMemory result = (ArrayMemory) array.toImmutable();
int i = 2;
Set<Integer> used = recursive ? new HashSet<Integer>() : null;
for (Memory el : arrays) {
if (!el.isArray()) {
env.warning(trace, "Argument %s is not an array", i);
continue;
}
if (used != null)
used.add(el.getPointer(true));
result.merge((ArrayMemory) el, recursive, used);
if (used != null)
used.remove(el.getPointer(true));
i++;
}
return result.toConstant();
}
public static Memory array_merge(Environment env, TraceInfo trace, Memory array, Memory... arrays) {
return _array_merge(env, trace, false, array, arrays);
}
public static Memory array_merge_recursive(Environment env, TraceInfo trace, Memory array, Memory... arrays) {
try {
return _array_merge(env, trace, true, array, arrays);
} catch (RecursiveException e) {
env.warning(trace, "recursion detected");
return Memory.NULL;
}
}
public static boolean shuffle(Environment env, TraceInfo trace, @Reference Memory value) {
if (expectingReference(env, trace, value, "shuffle") && expecting(env, trace, 1, value, ARRAY)) {
ArrayMemory array = value.toValue(ArrayMemory.class);
array.shuffle(MathFunctions.RANDOM);
return true;
} else {
return false;
}
}
public static Memory array_map(Environment env, TraceInfo trace, Memory callback, Memory _array, Memory... arrays)
throws Throwable {
Invoker invoker = expectingCallback(env, trace, 1, callback);
if (invoker == null) {
return Memory.NULL;
}
ArrayMemory result = new ArrayMemory();
ForeachIterator[] iterators;
if (!expecting(env, trace, 2, _array, ARRAY))
return Memory.NULL;
if (arrays == null) {
iterators = new ForeachIterator[]{_array.getNewIterator(env, false, false)};
} else {
iterators = new ForeachIterator[1 + arrays.length];
iterators[0] = _array.getNewIterator(env, false, false);
for (int i = 0; i < arrays.length; i++) {
if (!expecting(env, trace, i + 3, arrays[i], ARRAY))
return Memory.NULL;
iterators[i + 1] = arrays[i].getNewIterator(env, false, false);
}
}
Memory[] args = new Memory[iterators.length];
while (true) {
int i = 0;
boolean done = true;
for (ForeachIterator iterator : iterators) {
if (iterator.next()) {
args[i] = iterator.getValue();
done = false;
} else
args[i] = Memory.NULL;
i++;
}
if (done)
break;
result.add(invoker.call(args));
}
return result.toConstant();
}
public static Memory array_filter(Environment env, TraceInfo trace, Memory input, Memory callback)
throws Throwable {
if (!expecting(env, trace, 1, input, ARRAY)) {
return Memory.NULL;
}
Invoker invoker = null;
if (callback != null && callback.toBoolean()) {
invoker = expectingCallback(env, trace, 2, callback);
if (invoker == null)
return Memory.NULL;
}
ArrayMemory result = new ArrayMemory();
ForeachIterator iterator = input.getNewIterator(env, true, false);
while (iterator.next()) {
Object key = iterator.getKey();
Memory value = iterator.getValue();
if (invoker == null) {
if (!value.toBoolean())
continue;
} else if (!invoker.call(value).toBoolean())
continue;
result.put(key, value.toImmutable());
}
return result.toConstant();
}
public static Memory array_filter(Environment env, TraceInfo trace, Memory input)
throws Throwable {
return array_filter(env, trace, input, null);
}
public static Memory array_reduce(Environment env, TraceInfo trace, Memory input, Memory callback,
Memory initial)
throws Throwable {
if (!expecting(env, trace, 1, input, ARRAY))
return Memory.NULL;
Invoker invoker = expectingCallback(env, trace, 2, callback);
if (invoker == null)
return Memory.NULL;
ArrayMemory array = input.toValue(ArrayMemory.class);
if (array.size() == 0)
return Memory.NULL;
Memory result = initial;
ForeachIterator iterator = array.getNewIterator(env, true, false);
while (iterator.next()) {
Memory el = iterator.getValue();
result = invoker.call(result, el);
}
return result.toValue();
}
public static Memory array_reduce(Environment env, TraceInfo trace, Memory input, Memory callback)
throws Throwable {
return array_reduce(env, trace, input, callback, Memory.NULL);
}
public static boolean array_walk(Environment env, TraceInfo trace, @Reference Memory input, Memory callback,
Memory userData) throws Throwable {
if (!expectingReference(env, trace, input, "array_walk"))
return false;
if (!expecting(env, trace, 1, input, ARRAY))
return false;
Invoker invoker = expectingCallback(env, trace, 2, callback);
if (invoker == null)
return false;
ForeachIterator iterator = input.getNewIterator(env, true, false);
while (iterator.next()) {
Memory item = iterator.getValue();
Memory key = iterator.getMemoryKey();
invoker.call(item, key, userData);
}
return true;
}
public static boolean array_walk(Environment env, TraceInfo trace, @Reference Memory input, Memory callback)
throws Throwable {
return array_walk(env, trace, input, callback, Memory.NULL);
}
public static boolean _array_walk_recursive(Environment env, TraceInfo trace,
Memory input,
Invoker invoker, Memory userData, Set<Integer> used)
throws Throwable {
if (used == null)
used = new HashSet<Integer>();
ForeachIterator iterator = input.getNewIterator(env, true, false);
while (iterator.next()) {
Memory item = iterator.getValue();
if (item.isArray()) {
if (used.add(item.getPointer())) {
boolean result = _array_walk_recursive(env, trace, item, invoker, userData, used);
used.remove(item.getPointer());
if (!result)
return false;
} else {
env.warning(trace, "array_walk_recursive(): recursion detected");
}
} else {
Memory key = iterator.getMemoryKey();
invoker.call(item, key, userData);
}
}
return true;
}
public static boolean array_walk_recursive(Environment env, TraceInfo trace, @Reference Memory input,
Memory callback, Memory userData)
throws Throwable {
if (!expectingReference(env, trace, input, "array_walk_recursive"))
return false;
if (!expecting(env, trace, 1, input, ARRAY))
return false;
Invoker invoker = expectingCallback(env, trace, 2, callback);
if (invoker == null)
return false;
Set<Integer> used = new HashSet<Integer>();
used.add(input.getPointer());
return _array_walk_recursive(env, trace, input, invoker, userData, used);
}
public static boolean array_walk_recursive(Environment env, TraceInfo trace, Memory input,
Memory callback)
throws Throwable {
return array_walk_recursive(env, trace, input, callback, Memory.NULL);
}
public static Memory array_flip(Environment env, TraceInfo trace, Memory input) {
if (!expecting(env, trace, 1, input, ARRAY))
return Memory.NULL;
ArrayMemory result = new ArrayMemory();
ForeachIterator iterator = input.getNewIterator(env, false, false);
while (iterator.next())
result.put(ArrayMemory.toKey(iterator.getValue()), iterator.getMemoryKey());
return result.toConstant();
}
public static Memory array_reverse(Environment env, TraceInfo trace, Memory input, boolean saveKeys) {
if (!expecting(env, trace, 1, input, ARRAY))
return Memory.NULL;
ArrayMemory array = input.toValue(ArrayMemory.class);
ArrayMemory result = new ArrayMemory();
ForeachIterator iterator = input.getNewIterator(env, false, false);
Memory[] values = new Memory[array.size()];
Object[] keys = saveKeys ? new Object[values.length] : null;
int i = 0;
while (iterator.next()) {
if (saveKeys)
keys[i] = iterator.getKey();
values[i] = iterator.getValue().toImmutable();
i++;
}
for (i = values.length - 1; i >= 0; i--) {
if (saveKeys)
result.put(keys[i], values[i]);
else
result.add(values[i]);
}
return result.toConstant();
}
public static Memory array_reverse(Environment env, TraceInfo trace, Memory input) {
return array_reverse(env, trace, input, false);
}
public static Memory array_rand(Environment env, TraceInfo trace, Memory input, int numReq) {
if (!expecting(env, trace, 1, input, ARRAY))
return Memory.NULL;
ArrayMemory array = input.toValue(ArrayMemory.class);
int size = array.size();
if (size < numReq || numReq < 1) {
env.warning(trace, "array_rand(): Second argument has to be between 1 and the number of elements in the array");
return Memory.NULL;
}
int i;
if (numReq == 1) {
return array.getRandomElementKey(MathFunctions.RANDOM);
} else {
ForeachIterator iterator = input.getNewIterator(env, false, false);
Set<Integer> rands = new HashSet<Integer>();
for (i = 0; i < numReq; i++) {
while (!rands.add(MathFunctions.rand(0, size - 1).toInteger())) ;
}
ArrayMemory result = new ArrayMemory();
i = -1;
while (iterator.next()) {
i++;
if (!rands.contains(i))
continue;
result.add(iterator.getMemoryKey());
if (result.size() >= numReq)
break;
}
return result.toConstant();
}
}
public static Memory array_rand(Environment env, TraceInfo trace, Memory input) {
return array_rand(env, trace, input, 1);
}
public static Memory array_pop(Environment env, TraceInfo trace, @Reference Memory input) {
if (!expectingReference(env, trace, input, "array_pop"))
return Memory.NULL;
if (!expecting(env, trace, 1, input, ARRAY))
return Memory.NULL;
Memory value = input.toValue(ArrayMemory.class).pop();
return value == null ? Memory.NULL : value.toImmutable();
}
public static Memory array_push(Environment env, TraceInfo trace, @Reference Memory input, Memory var,
Memory... args) {
if (!expectingReference(env, trace, input, "array_push"))
return Memory.NULL;
if (!expecting(env, trace, 1, input, ARRAY))
return Memory.NULL;
ArrayMemory array = input.toValue(ArrayMemory.class);
array.add(var);
if (args != null)
for (Memory arg : args)
array.add(arg);
return LongMemory.valueOf(array.size());
}
public static Memory array_shift(Environment env, TraceInfo trace, @Reference Memory input) {
if (!expectingReference(env, trace, input, "array_shift"))
return Memory.NULL;
if (!expecting(env, trace, 1, input, ARRAY))
return Memory.NULL;
Memory value = input.toValue(ArrayMemory.class).shift();
return value == null ? Memory.NULL : value.toImmutable();
}
public static Memory array_unshift(Environment env, TraceInfo trace, @Reference Memory input, Memory var,
Memory... args) {
if (!expectingReference(env, trace, input, "array_unshift"))
return Memory.NULL;
if (!expecting(env, trace, 1, input, ARRAY))
return Memory.NULL;
ArrayMemory array = input.toValue(ArrayMemory.class);
Memory[] tmp = args == null ? new Memory[]{var} : new Memory[args.length + 1];
if (args != null) {
tmp[0] = var;
System.arraycopy(args, 0, tmp, 1, args.length);
}
array.unshift(tmp);
return LongMemory.valueOf(array.size());
}
public static Memory array_values(Environment env, TraceInfo trace, Memory input) {
if (!expecting(env, trace, 1, input, ARRAY))
return Memory.NULL;
Memory[] values = input.toValue(ArrayMemory.class).values();
return ArrayMemory.of(values).toConstant();
}
public static Memory array_keys(Environment env, TraceInfo trace, Memory input) {
return array_keys(env, trace, input, null);
}
public static Memory array_keys(Environment env, TraceInfo trace, Memory input, Memory search) {
return array_keys(env, trace, input, search, false);
}
public static Memory array_keys(Environment env, TraceInfo trace, Memory input, Memory search, boolean strict) {
if (!expecting(env, trace, 1, input, ARRAY))
return Memory.NULL;
ArrayMemory result = new ArrayMemory();
ForeachIterator iterator = input.getNewIterator(env, false, false);
while (iterator.next()) {
if (search == null) {
result.add(iterator.getMemoryKey());
} else {
if (strict && iterator.getValue().identical(search)) {
result.add(iterator.getMemoryKey());
} else if (iterator.getValue().equal(search)) {
result.add(iterator.getMemoryKey());
}
}
}
return result.toConstant();
}
public static Memory array_pad(Environment env, TraceInfo trace, Memory input,
int padSize, Memory padValue) {
if (expecting(env, trace, 1, input, ARRAY)) {
ArrayMemory array = input.toValue(ArrayMemory.class);
int size = array.size();
int needSize = Math.abs(padSize);
ArrayMemory result = input.toImmutable().toValue(ArrayMemory.class);
if (size == needSize)
return result;
result.checkCopied();
int count = needSize - size;
if (padSize >= 0) {
for (int i = 0; i < needSize - size; i++)
result.add(padValue);
} else {
result.unshift(padValue, count);
}
return result;
} else
return Memory.NULL;
}
public static Memory array_product(Environment env, TraceInfo trace, Memory input) {
if (expecting(env, trace, 1, input, ARRAY)) {
ForeachIterator iterator = input.getNewIterator(env, false, false);
Memory result = Memory.CONST_INT_1;
while (iterator.next()) {
result = result.mul(iterator.getValue());
}
return result;
} else
return Memory.NULL;
}
public static Memory array_sum(Environment env, TraceInfo trace, Memory input) {
if (expecting(env, trace, 1, input, ARRAY)) {
ForeachIterator iterator = input.getNewIterator(env, false, false);
Memory result = Memory.CONST_INT_0;
while (iterator.next()) {
result = result.plus(iterator.getValue());
}
return result;
} else
return Memory.NULL;
}
public static Memory array_change_key_case(Environment env, TraceInfo trace, Memory input, int _case) {
if (expecting(env, trace, 1, input, ARRAY)) {
ArrayMemory result = new ArrayMemory();
ForeachIterator iterator = input.getNewIterator(env, false, false);
while (iterator.next()) {
Object key = iterator.getKey();
if (key instanceof String) {
String str = (String) key;
str = _case == 0 ? str.toLowerCase() : str.toUpperCase();
result.put(str, iterator.getValue().toImmutable());
} else
result.put(key, iterator.getValue().toImmutable());
}
return result.toConstant();
}
return Memory.NULL;
}
public static Memory array_change_key_case(Environment env, TraceInfo trace, Memory input) {
return array_change_key_case(env, trace, input, 0);
}
public static Memory array_chunk(Environment env, TraceInfo trace, Memory input, int size,
boolean saveKeys) {
if (expecting(env, trace, 1, input, ARRAY)) {
if (size < 1) {
env.warning(trace, "array_chunk(): Size parameter expected to be greater than 0");
return Memory.NULL;
}
ArrayMemory result = new ArrayMemory();
ArrayMemory item = null;
ForeachIterator iterator = input.getNewIterator(env, false, false);
int i = 0;
while (iterator.next()) {
if (i == 0) {
item = new ArrayMemory();
result.add(item);
}
if (saveKeys) {
item.put(iterator.getKey(), iterator.getValue().toImmutable());
} else
item.add(iterator.getValue().toImmutable());
if (++i == size)
i = 0;
}
return result.toConstant();
} else
return Memory.NULL;
}
public static Memory array_chunk(Environment env, TraceInfo trace, Memory input, int size) {
return array_chunk(env, trace, input, size, false);
}
public static Memory array_column(Environment env, TraceInfo trace, Memory input, Memory columnKey,
Memory indexKey) {
if (expecting(env, trace, 1, input, ARRAY)) {
if (columnKey.isNull() && indexKey.isNull())
return array_values(env, trace, input);
ArrayMemory result = new ArrayMemory();
ForeachIterator iterator = input.getNewIterator(env, false, false);
while (iterator.next()) {
Memory value = iterator.getValue();
if (indexKey.isNull()) {
result.add(value.valueOfIndex(columnKey).toImmutable());
} else {
if (columnKey.isNull())
result.refOfIndex(value.valueOfIndex(indexKey)).assign(value.toImmutable());
else
result.refOfIndex(value.valueOfIndex(indexKey)).assign(value.valueOfIndex(columnKey));
}
}
return result.toConstant();
} else
return Memory.NULL;
}
public static Memory array_column(Environment env, TraceInfo trace, Memory input, Memory columnKey) {
return array_column(env, trace, input, columnKey, Memory.NULL);
}
public static Memory array_combine(Environment env, TraceInfo trace, Memory keys, Memory values) {
if (expecting(env, trace, 1, keys, ARRAY) && expecting(env, trace, 2, values, ARRAY)) {
ArrayMemory _keys = keys.toValue(ArrayMemory.class);
ArrayMemory _values = values.toValue(ArrayMemory.class);
int size1 = _keys.size();
int size2 = _values.size();
if (size1 != size2) {
env.warning(trace, "array_combine(): Both parameters should have an equal number of elements");
return Memory.FALSE;
}
ArrayMemory result = new ArrayMemory();
if (size1 == 0)
return result.toConstant();
ForeachIterator iteratorKeys = _keys.getNewIterator(env, false, false);
ForeachIterator iteratorValues = _values.getNewIterator(env, false, false);
while (iteratorKeys.next()) {
iteratorValues.next();
result.refOfIndex(iteratorKeys.getValue())
.assign(iteratorValues.getValue().toImmutable());
}
return result.toConstant();
} else
return Memory.FALSE;
}
public static Memory array_count_values(Environment env, TraceInfo trace, Memory input) {
if (expecting(env, trace, 1, input, ARRAY)) {
ArrayMemory counts = new ArrayMemory();
ForeachIterator iterator = input.getNewIterator(env, false, false);
boolean warning = false;
while (iterator.next()) {
Memory value = iterator.getValue();
switch (value.getRealType()) {
case INT:
case STRING:
Memory count = counts.getOrCreate(value);
count.assign(count.inc());
break;
default:
if (!warning) {
env.warning(trace, "array_count_values(): Can only count STRING and INTEGER values!");
warning = true;
}
}
}
return counts.toConstant();
} else
return Memory.NULL;
}
public static Memory array_search(Environment env, TraceInfo trace, Memory input, Memory needle, boolean strict) {
if (expecting(env, trace, 1, input, ARRAY)) {
ForeachIterator iterator = input.getNewIterator(env, false, false);
while (iterator.next()) {
Memory value = iterator.getValue();
if (strict && needle.identical(value)) {
return iterator.getMemoryKey();
} else if (needle.equal(value)) {
return iterator.getMemoryKey();
}
}
return Memory.FALSE;
} else {
return Memory.FALSE;
}
}
private static Memory _range_double(Environment env, TraceInfo trace, double low, double high, double step) {
ArrayMemory result = new ArrayMemory();
double value;
long i = 0;
boolean error_occurred = false;
if (step < 0.0) {
step *= -1;
}
if (low > high) { /* Negative steps */
if (low - high < step || step <= 0) {
error_occurred = true;
} else {
for (value = low; value >= high; value = low - (++i * step)) {
result.add(value);
}
}
} else if (high > low) { /* Positive steps */
if (high - low < step || step <= 0) {
error_occurred = true;
} else {
for (value = low; value <= high; value = low + (++i * step)) {
result.add(value);
}
}
} else {
result.add(low);
}
if (error_occurred) {
env.warning(trace, "range(): step exceeds the specified range");
return Memory.FALSE;
}
return result.toConstant();
}
private static Memory _range_long(Environment env, TraceInfo trace, long low, long high, long step) {
ArrayMemory result = new ArrayMemory();
boolean error_occurred = false;
if (step < 0) {
step *= -1;
}
if (low > high) { /* Negative steps */
if (low - high < step || step <= 0) {
error_occurred = true;
} else {
for (; low >= high; low -= step) {
result.add(low);
}
}
} else if (high > low) { /* Positive steps */
if (high - low < step || step <= 0) {
error_occurred = true;
} else {
for (; low <= high; low += step) {
result.add(low);
}
}
} else {
result.add(low);
}
if (error_occurred) {
env.warning(trace, "range(): step exceeds the specified range");
return Memory.FALSE;
}
return result.toConstant();
}
public static Memory range(Environment env, TraceInfo trace, Memory low, Memory high, Memory step) {
if (low.getRealType() == Memory.Type.DOUBLE || high.getRealType() == Memory.Type.DOUBLE || step.getRealType() == Memory.Type.DOUBLE) {
return _range_double(env, trace, low.toDouble(), high.toDouble(), step.toDouble());
} else {
return _range_long(env, trace, low.toLong(), high.toLong(), step.toLong());
}
}
public static Memory range(Environment env, TraceInfo trace, Memory low, Memory high) {
return range(env, trace, low, high, Memory.CONST_INT_1);
}
public static Memory array_fill(int start, int num, Memory value) {
ArrayMemory result = new ArrayMemory();
if (start >= 0) {
for (int i = start; i < start + num; i++) {
if (start == 0) {
result.add(value);
} else {
result.refOfIndex(i).assign(value);
}
}
} else {
result.refOfIndex(start).assign(value);
for (int i = 0; i < num - 1; i++) {
result.refOfIndex(i).assign(value);
}
}
return result.toConstant();
}
public static Memory array_fill_keys(Environment env, TraceInfo trace, Memory keys, Memory value) {
if (expecting(env, trace, 1, keys, ARRAY)) {
ForeachIterator iterator = keys.getNewIterator(env);
ArrayMemory result = new ArrayMemory();
while (iterator.next()) {
result.refOfIndex(iterator.getValue()).assign(value.toImmutable());
}
return result.toConstant();
} else {
return new ArrayMemory().toConstant();
}
}
public static Memory array_unique(Environment env, TraceInfo trace, Memory array) {
return array_unique(env, trace, array, 0);
}
public static Memory array_unique(Environment env, TraceInfo trace, Memory array, int flag) {
if (expecting(env, trace, 1, array, ARRAY)) {
Set<Object> keys = new TreeSet<>();
ArrayMemory newArray = new ArrayMemory();
ForeachIterator iterator = array.getNewIterator(env);
while (iterator.next()) {
Object key;
switch (flag) {
case 1:
key = iterator.getValue().toLong();
break;
case 2:
key = iterator.getValue().toBinaryString();
break;
case 5:
key = iterator.getValue().toString();
break;
case 0:
default:
key = iterator.getValue().toString();
break;
}
if (keys.add(key)) {
newArray.put(iterator.getKey(), iterator.getValue().toImmutable());
}
}
return newArray.toConstant();
}
return Memory.NULL;
}
public static Memory array_replace(Environment env, TraceInfo trace, Memory array, Memory replacement, Memory... replacements) {
if (expecting(env, trace, 1, array, ARRAY) && expecting(env, trace, 2, replacement, ARRAY)) {
ArrayMemory result = array.toValue(ArrayMemory.class).duplicate();
for (int i = 0; i < (replacements == null ? 0 : replacements.length) + 1; i++) {
if (i > 0) {
replacement = replacements[i - 1];
if (!expecting(env, trace, i + 2, replacement, ARRAY)) {
return Memory.NULL;
}
}
ForeachIterator iterator = replacement.getNewIterator(env);
while (iterator.next()) {
result.put(iterator.getKey(), iterator.getValue().toImmutable());
}
}
return result.toConstant();
}
return Memory.NULL;
}
interface ArrayDiffCallback {
boolean apply(Memory keyValue, Memory value, Memory keyComparable, Memory comparable) throws Throwable;
}
protected static Memory _array_diff_impl(Environment env, TraceInfo trace, Memory array1, Memory array, Memory[] arrays, ArrayDiffCallback callback) throws Throwable {
if (expecting(env, trace, 1, array1, ARRAY) && expecting(env, trace, 2, array, ARRAY)) {
ForeachIterator iterator = array1.getNewIterator(env);
ArrayMemory result = new ArrayMemory();
while (iterator.next()) {
Memory value = iterator.getValue();
boolean exists = false;
for (int i = 0; i < (arrays == null ? 0 : arrays.length) +1; i++){
if (i > 0) {
array = arrays[i - 1];
if (!expecting(env, trace, i + 2, array, ARRAY)) {
return Memory.NULL;
}
}
ForeachIterator newIterator = array.getNewIterator(env);
while (newIterator.next()) {
if (callback.apply(iterator.getMemoryKey(), value, newIterator.getMemoryKey(), newIterator.getValue())) {
exists = true;
break;
}
}
if (exists) break;
}
if (!exists) {
result.put(iterator.getKey(), value.toImmutable());
}
}
return result.toConstant();
}
return Memory.NULL;
}
public static Memory array_diff(Environment env, TraceInfo trace, Memory array1, Memory array, Memory... arrays) throws Throwable {
return _array_diff_impl(env, trace, array1, array, arrays, new ArrayDiffCallback() {
@Override
public boolean apply(Memory keyValue, Memory value, Memory keyComparable, Memory comparable) {
return value.toString().equals(comparable.toString());
}
});
}
public static Memory array_diff_key(Environment env, TraceInfo trace, Memory array1, Memory array, Memory... arrays) throws Throwable {
return _array_diff_impl(env, trace, array1, array, arrays, new ArrayDiffCallback() {
@Override
public boolean apply(Memory keyValue, Memory value, Memory keyComparable, Memory comparable) {
return keyValue.equal(keyComparable);
}
});
}
public static Memory array_diff_assoc(Environment env, TraceInfo trace, Memory array1, Memory array, Memory... arrays) throws Throwable {
return _array_diff_impl(env, trace, array1, array, arrays, new ArrayDiffCallback() {
@Override
public boolean apply(Memory keyValue, Memory value, Memory keyComparable, Memory comparable) {
return keyValue.equal(keyComparable) && value.toString().equals(comparable.toString());
}
});
}
protected static Memory _array_udiff_impl(Environment env, TraceInfo trace, Memory array1, Memory array, final boolean assoc, Memory... arrays) throws Throwable {
if (arrays == null) {
expectingCallback(env, trace, 3, Memory.NULL);
return Memory.NULL;
}
Memory callback = arrays[arrays.length - 1];
final Invoker expectingCallback = expectingCallback(env, trace, arrays.length + 2, callback);
if (expectingCallback != null) {
return _array_diff_impl(env, trace, array1, array, Arrays.copyOf(arrays, arrays.length - 1), new ArrayDiffCallback() {
@Override
public boolean apply(Memory keyValue, Memory value, Memory keyComparable, Memory comparable) throws Throwable {
if (assoc && keyValue.notEqual(keyComparable)) {
return false;
}
Memory memory = expectingCallback.call(value, comparable);
return memory.toInteger() == 0;
}
});
} else {
return Memory.NULL;
}
}
public static Memory array_udiff(Environment env, TraceInfo trace, Memory array1, Memory array, Memory... arrays) throws Throwable {
return _array_udiff_impl(env, trace, array1, array, false, arrays);
}
public static Memory array_udiff_assoc(Environment env, TraceInfo trace, Memory array1, Memory array, Memory... arrays) throws Throwable {
return _array_udiff_impl(env, trace, array1, array, true, arrays);
}
public static Memory array_slice(Environment env, TraceInfo trace, Memory array, int offset) {
return array_slice(env, trace, array, offset, Memory.NULL);
}
public static Memory array_slice(Environment env, TraceInfo trace, Memory array, int offset, Memory length) {
return array_slice(env, trace, array, offset, length, false);
}
public static Memory array_slice(Environment env, TraceInfo trace, Memory array, int offset, Memory length, boolean preserveKeys) {
if (expecting(env, trace, 1, array, ARRAY)) {
ArrayMemory arrayMemory = array.toValue(ArrayMemory.class);
try {
return (length.isNull() ? arrayMemory.slice(offset, preserveKeys) : arrayMemory.slice(offset, length.toInteger(), preserveKeys)).toConstant();
} catch (IndexOutOfBoundsException e) {
return new ArrayMemory().toConstant();
}
} else {
return Memory.NULL;
}
}
protected static Comparator<Memory> makeComparatorForUSort(final Environment env, final Invoker invoker) {
return new Comparator<Memory>() {
@Override
public int compare(Memory o1, Memory o2) {
if (invoker == null) {
return 0;
}
try {
return invoker.call(o1, o2).toInteger();
} catch (Throwable throwable) {
env.forwardThrow(throwable);
return 0;
}
}
};
}
protected static Comparator makeComparatorForSort(int flags, final boolean revert) {
switch (flags) {
case ArrayConstants.SORT_NUMERIC:
return new Comparator<Memory>() {
@Override
public int compare(Memory o1, Memory o2) {
o1 = o1.toNumeric();
o2 = o2.toNumeric();
return o1.equal(o2) ? 0 : (o1.greater(o2) ? 1 : -1) * (revert ? -1 : 1);
}
};
case SORT_STRING | SORT_FLAG_CASE:
case SORT_LOCALE_STRING | SORT_FLAG_CASE:
return new Comparator<Memory>() {
@Override
public int compare(Memory o1, Memory o2) {
String s1 = o1.toString();
String s2 = o2.toString();
int cmp = s1.compareToIgnoreCase(s2);
return cmp == 0 ? 0 : (cmp < 0 ? -1 : 1) * (revert ? -1 : 1);
}
};
case SORT_STRING:
case SORT_LOCALE_STRING:
return new Comparator<Memory>() {
@Override
public int compare(Memory o1, Memory o2) {
String s1 = o1.toString();
String s2 = o2.toString();
int cmp = s1.compareTo(s2);
return cmp == 0 ? 0 : (cmp < 0 ? -1 : 1) * (revert ? -1 : 1);
}
};
case SORT_NATURAL | SORT_FLAG_CASE:
return new NaturalOrderComparator(true, revert);
case SORT_NATURAL:
return new NaturalOrderComparator(false, revert);
case ArrayConstants.SORT_REGULAR:
default:
return new Comparator<Memory>() {
@Override
public int compare(Memory o1, Memory o2) {
return o1.compareTo(o2) * (revert ? -1 : 1);
}
};
}
}
protected static boolean _sort_impl(Environment env, TraceInfo trace, @Reference Memory array, int flags, boolean revert) {
return _sort_impl(env, trace, array, makeComparatorForSort(flags, revert));
}
protected static boolean _sort_impl(Environment env, TraceInfo trace, @Reference Memory array, Comparator comparator) {
if (expecting(env, trace, 1, array, ARRAY)) {
ArrayMemory arrayMemory = array.toValue(ArrayMemory.class);
Memory[] values = arrayMemory.values();
arrayMemory.clear();
try {
Arrays.sort(values, comparator);
} catch (IllegalArgumentException e) {
return false;
}
for (Memory value : values) {
arrayMemory.add(value);
}
return true;
} else {
return false;
}
}
public static boolean sort(Environment env, TraceInfo trace, @Reference Memory array) {
return sort(env, trace, array, 0);
}
public static boolean sort(Environment env, TraceInfo trace, @Reference Memory array, int flags) {
return _sort_impl(env, trace, array, flags, false);
}
public static boolean rsort(Environment env, TraceInfo trace, @Reference Memory array) {
return rsort(env, trace, array, 0);
}
public static boolean rsort(Environment env, TraceInfo trace, @Reference Memory array, int flags) {
return _sort_impl(env, trace, array, flags, true);
}
protected static boolean _asort_impl(Environment env, TraceInfo trace, @Reference Memory array, int flags, boolean revert) {
return _asort_impl(env, trace, array, makeComparatorForSort(flags, revert));
}
protected static boolean _asort_impl(Environment env, TraceInfo trace, @Reference Memory array, Comparator comparator) {
if (expecting(env, trace, 1, array, ARRAY)) {
ArrayMemory arrayMemory = array.toValue(ArrayMemory.class);
Memory[] values = new Memory[arrayMemory.size()];
ForeachIterator iterator = arrayMemory.getNewIterator(env);
int i = 0;
while (iterator.next()) {
values[i++] = new KeyValueMemory(iterator.getMemoryKey(), iterator.getValue());
}
arrayMemory.clear();
try {
Arrays.sort(values, comparator);
} catch (IllegalArgumentException e) {
return false;
}
for (Memory value : values) {
arrayMemory.add(value);
}
return true;
} else {
return false;
}
}
public static boolean asort(Environment env, TraceInfo trace, @Reference Memory array) {
return asort(env, trace, array, 0);
}
public static boolean asort(Environment env, TraceInfo trace, @Reference Memory array, int flags) {
return _asort_impl(env, trace, array, flags, false);
}
public static boolean arsort(Environment env, TraceInfo trace, @Reference Memory array) {
return arsort(env, trace, array, 0);
}
public static boolean arsort(Environment env, TraceInfo trace, @Reference Memory array, int flags) {
return _asort_impl(env, trace, array, flags, true);
}
public static boolean natsort(Environment env, TraceInfo trace, @Reference Memory array) {
return _asort_impl(env, trace, array, SORT_NATURAL, false);
}
public static boolean natcasesort(Environment env, TraceInfo trace, @Reference Memory array) {
return _asort_impl(env, trace, array, SORT_NATURAL | SORT_FLAG_CASE, false);
}
protected static boolean _ksort_impl(Environment env, TraceInfo trace, @Reference Memory array, int flags, boolean revert) {
return _ksort_impl(env, trace, array, makeComparatorForSort(flags, revert));
}
protected static boolean _ksort_impl(Environment env, TraceInfo trace, @Reference Memory array, Comparator comparator) {
if (expecting(env, trace, 1, array, ARRAY)) {
ArrayMemory arrayMemory = array.toValue(ArrayMemory.class);
Memory[] values = new Memory[arrayMemory.size()];
ForeachIterator iterator = arrayMemory.getNewIterator(env);
int i = 0;
while (iterator.next()) {
values[i++] = iterator.getMemoryKey();
}
//arrayMemory.clear();
try {
Arrays.sort(values, comparator);
} catch (IllegalArgumentException e) {
return false;
}
ArrayMemory newArray = new ArrayMemory();
for (Memory value : values) {
newArray.refOfIndex(value).assign(arrayMemory.valueOfIndex(value));
arrayMemory.remove(value);
}
array.assign(newArray);
return true;
} else {
return false;
}
}
public static boolean ksort(Environment env, TraceInfo trace, @Reference Memory array) {
return ksort(env, trace, array, 0);
}
public static boolean ksort(Environment env, TraceInfo trace, @Reference Memory array, int flags) {
return _ksort_impl(env, trace, array, flags, false);
}
public static boolean krsort(Environment env, TraceInfo trace, @Reference Memory array) {
return krsort(env, trace, array, 0);
}
public static boolean krsort(Environment env, TraceInfo trace, @Reference Memory array, int flags) {
return _ksort_impl(env, trace, array, flags, true);
}
protected static boolean _usort_impl(Environment env, TraceInfo trace, @Reference Memory array, Memory callback) {
Invoker invoker = expectingCallback(env, trace, 2, callback);
if (invoker != null) {
return _sort_impl(env, trace, array, makeComparatorForUSort(env, invoker));
} else {
return false;
}
}
public static boolean usort(Environment env, TraceInfo trace, @Reference Memory array, Memory callback) {
return _usort_impl(env, trace, array, callback);
}
protected static boolean _uasort_impl(Environment env, TraceInfo trace, @Reference Memory array, Memory callback) {
Invoker invoker = expectingCallback(env, trace, 2, callback);
if (invoker != null) {
return _asort_impl(env, trace, array, makeComparatorForUSort(env, invoker));
} else {
return false;
}
}
public static boolean uasort(Environment env, TraceInfo trace, @Reference Memory array, Memory callback) {
return _uasort_impl(env, trace, array, callback);
}
protected static boolean _uksort_impl(Environment env, TraceInfo trace, @Reference Memory array, Memory callback) {
Invoker invoker = expectingCallback(env, trace, 2, callback);
if (invoker != null) {
return _ksort_impl(env, trace, array, makeComparatorForUSort(env, invoker));
} else {
return false;
}
}
public static boolean uksort(Environment env, TraceInfo trace, @Reference Memory array, Memory callback) {
return _uksort_impl(env, trace, array, callback);
}
}