Добавлена функция std::range

This commit is contained in:
Victor 2016-06-28 14:33:11 +03:00
parent 66bf40bfbc
commit 6156c507d8
4 changed files with 316 additions and 2 deletions

View File

@ -6,10 +6,11 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
/** /**
* Represents array type.
* *
* @author aNNiMON * @author aNNiMON
*/ */
public final class ArrayValue implements Value, Iterable<Value> { public class ArrayValue implements Value, Iterable<Value> {
public static ArrayValue of(byte[] array) { public static ArrayValue of(byte[] array) {
final int size = array.length; final int size = array.length;

View File

@ -0,0 +1,218 @@
package com.annimon.ownlang.lib.modules.functions;
import com.annimon.ownlang.lib.*;
import java.util.Iterator;
public final class std_range implements Function {
@Override
public Value execute(Value... args) {
Arguments.checkRange(1, 3, args.length);
final long from, to, step;
switch (args.length) {
default:
case 1:
from = 0;
to = getLong(args[0]);
step = 1;
break;
case 2:
from = getLong(args[0]);
to = getLong(args[1]);
step = 1;
break;
case 3:
from = getLong(args[0]);
to = getLong(args[1]);
step = getLong(args[2]);
break;
}
return RangeValue.of(from, to, step);
}
private static long getLong(Value v) {
if (v.type() == Types.NUMBER) {
return ((NumberValue) v).asLong();
}
return v.asInt();
}
private static class RangeValue extends ArrayValue {
public static ArrayValue of(long from, long to, long step) {
boolean isInvalid = false;
isInvalid = isInvalid || (step == 0);
isInvalid = isInvalid || ((step > 0) && (from >= to));
isInvalid = isInvalid || ((step < 0) && (to >= from));
if (isInvalid) return new ArrayValue(0);
return new RangeValue(from, to, step);
}
private final long from, to, step;
private final int size;
public RangeValue(long from, long to, long step) {
super(new Value[0]);
this.from = from;
this.to = to;
this.step = step;
// x = range(0, 10, 2)
// 0, 2, 4, 6, 8 | 0..10 step 2
// 0, 3, 6, 9 | 0..10 step 3
// 0, 4, 8 | 0..10 step 4
final long base = (from < to) ? (to - from) : (from - to);
final long absStep = (step < 0) ? -step : step;
this.size = (int) (base / absStep + (base % absStep == 0 ? 0 : 1));
}
@Override
public Value[] getCopyElements() {
final Value[] result = new Value[size];
int i = 0;
if (isIntegerRange()) {
final int toInt = (int) to;
final int stepInt = (int) step;
for (int value = (int) from; value < toInt; value += stepInt) {
result[i++] = NumberValue.of(value);
}
} else {
for (long value = from; value < to; value += step) {
result[i++] = NumberValue.of(value);
}
}
return result;
}
private boolean isIntegerRange() {
if (to > 0) {
return (to < Integer.MAX_VALUE) && (from > Integer.MIN_VALUE && to < Integer.MAX_VALUE);
}
return (to > Integer.MIN_VALUE) && (to > Integer.MIN_VALUE && from < Integer.MAX_VALUE);
}
@Override
public int size() {
return size;
}
@Override
public Value get(int index) {
if (isIntegerRange()) {
return NumberValue.of((int) (from + index * step));
}
return NumberValue.of(from + (long) index * step);
}
@Override
public void set(int index, Value value) {
// not implemented
}
@Override
public Object raw() {
return getCopyElements();
}
@Override
public String asString() {
if (size == 0) return "[]";
final StringBuilder sb = new StringBuilder();
sb.append('[').append(from);
for (long value = from + step; value < to; value += step) {
sb.append(", ").append(value);
}
sb.append(']');
return sb.toString();
}
@Override
public Iterator<Value> iterator() {
if (isIntegerRange()) {
final int toInt = (int) to;
final int stepInt = (int) step;
return new Iterator<Value>() {
int value = (int) from;
@Override
public boolean hasNext() {
return value < toInt;
}
@Override
public Value next() {
final int result = value;
value += stepInt;
return NumberValue.of(result);
}
};
}
return new Iterator<Value>() {
long value = from;
@Override
public boolean hasNext() {
return value < to;
}
@Override
public Value next() {
final long result = value;
value += step;
return NumberValue.of(result);
}
};
}
@Override
public int hashCode() {
int hash = 5;
hash = 59 * hash + (int) (this.from ^ (this.from >>> 32));
hash = 59 * hash + (int) (this.to ^ (this.to >>> 32));
hash = 59 * hash + (int) (this.step ^ (this.step >>> 32));
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass())
return false;
final RangeValue other = (RangeValue) obj;
if (this.from != other.from) return false;
if (this.to != other.to) return false;
if (this.step != other.step) return false;
return true;
}
@Override
public int compareTo(Value o) {
if (o.type() == Types.ARRAY) {
final int lengthCompare = Integer.compare(size(), ((ArrayValue) o).size());
if (lengthCompare != 0) return lengthCompare;
if (o instanceof RangeValue) {
final RangeValue o2 = ((RangeValue) o);
int compareResult;
compareResult = Long.compare(this.from, o2.from);
if (compareResult != 0) return compareResult;
compareResult = Long.compare(this.to, o2.to);
if (compareResult != 0) return compareResult;
}
}
return asString().compareTo(o.asString());
}
@Override
public String toString() {
if (step == 1) {
return String.format("range(%d, %d)", from, to);
}
return String.format("range(%d, %d, %d)", from, to, step);
}
}
}

View File

@ -47,5 +47,6 @@ public final class std implements Module {
Functions.set("arrayKeyExists", new std_arrayKeyExists()); Functions.set("arrayKeyExists", new std_arrayKeyExists());
Functions.set("arrayKeys", new std_arrayKeys()); Functions.set("arrayKeys", new std_arrayKeys());
Functions.set("arrayValues", new std_arrayValues()); Functions.set("arrayValues", new std_arrayValues());
Functions.set("range", new std_range());
} }
} }

View File

@ -0,0 +1,94 @@
use "std"
use "types"
use "functional"
def testRangeParams() {
x = range(10)
assertEquals(10, length(x))
assertEquals(0, x[0])
assertEquals(9, x[9])
}
def testRangeParamsFromTo() {
x = range(4, 10)
assertEquals(6, length(x))
assertEquals(4, x[0])
assertEquals(9, x[5])
}
def testRangeParamsWithStep() {
x = range(4, 10, 2)
assertEquals(3, length(x))
assertEquals(4, x[0])
assertEquals(8, x[2])
}
def testRangeParamsReversed() {
x = range(10, 4, -1)
assertEquals(6, length(x))
assertEquals(10, x[0])
assertEquals(5, x[5])
}
def testRangeLength() {
assertEquals(10, length(range(0, 10, 1)))
assertEquals(5, length(range(0, 10, 2)))
assertEquals(4, length(range(0, 10, 3)))
assertEquals(3, length(range(0, 10, 4)))
assertEquals(2, length(range(0, 10, 5)))
assertEquals(1, length(range(0, 10, 15)))
}
def testRangeReversedLength() {
assertEquals(10, length(range(10, 0, -1)))
assertEquals(5, length(range(10, 0, -2)))
assertEquals(4, length(range(10, 0, -3)))
assertEquals(3, length(range(10, 0, -4)))
assertEquals(2, length(range(10, 0, -5)))
assertEquals(1, length(range(10, 0, -15)))
}
def testRangeHuge() {
x = range(-1002003004005006007, 1002003004005006007)
assertEquals(-1002003004005006000, x[7])
x = range(-1002003004005006007, 1002003004005006007, 100000000000)
assertEquals(20040061, length(x))
x = range(-10000000, 20000000)
assertEquals(30000000, length(x))
assertEquals(0, x[10000000])
}
def testRangeAsString() {
x = range(1, 6)
assertEquals("[1, 2, 3, 4, 5]", string(x))
x = range(1, 6, 2)
assertEquals("[1, 3, 5]", string(x))
assertEquals(string([1,3,5]), string(x))
}
def testRangeIterate() {
sum = 0
for x : range(5) {
sum += x
}
assertEquals(10, sum)
}
def testRangeFunctionalForeach() {
i = 0
foreach(range(5), def(x) = assertEquals(i++, x))
}
def testRangeFunctionalReduce() {
sum = reduce(range(5), 0, def(x, y) = x + y)
assertEquals(10, sum)
}
def testRangeInvalid() {
assertEquals(0, length(range(-100)))
assertEquals(0, length(range(0, -100, 1)))
assertEquals(0, length(range(0, 100, 0)))
}