Skip to content

Commit 6156c50

Browse files
committed
Добавлена функция std::range
1 parent 66bf40b commit 6156c50

File tree

4 files changed

+316
-2
lines changed

4 files changed

+316
-2
lines changed

src/com/annimon/ownlang/lib/ArrayValue.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
import java.util.List;
77

88
/**
9-
*
9+
* Represents array type.
10+
*
1011
* @author aNNiMON
1112
*/
12-
public final class ArrayValue implements Value, Iterable<Value> {
13+
public class ArrayValue implements Value, Iterable<Value> {
1314

1415
public static ArrayValue of(byte[] array) {
1516
final int size = array.length;
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
package com.annimon.ownlang.lib.modules.functions;
2+
3+
import com.annimon.ownlang.lib.*;
4+
import java.util.Iterator;
5+
6+
public final class std_range implements Function {
7+
8+
@Override
9+
public Value execute(Value... args) {
10+
Arguments.checkRange(1, 3, args.length);
11+
12+
final long from, to, step;
13+
switch (args.length) {
14+
default:
15+
case 1:
16+
from = 0;
17+
to = getLong(args[0]);
18+
step = 1;
19+
break;
20+
case 2:
21+
from = getLong(args[0]);
22+
to = getLong(args[1]);
23+
step = 1;
24+
break;
25+
case 3:
26+
from = getLong(args[0]);
27+
to = getLong(args[1]);
28+
step = getLong(args[2]);
29+
break;
30+
}
31+
return RangeValue.of(from, to, step);
32+
}
33+
34+
private static long getLong(Value v) {
35+
if (v.type() == Types.NUMBER) {
36+
return ((NumberValue) v).asLong();
37+
}
38+
return v.asInt();
39+
}
40+
41+
private static class RangeValue extends ArrayValue {
42+
43+
public static ArrayValue of(long from, long to, long step) {
44+
boolean isInvalid = false;
45+
isInvalid = isInvalid || (step == 0);
46+
isInvalid = isInvalid || ((step > 0) && (from >= to));
47+
isInvalid = isInvalid || ((step < 0) && (to >= from));
48+
if (isInvalid) return new ArrayValue(0);
49+
return new RangeValue(from, to, step);
50+
}
51+
52+
private final long from, to, step;
53+
private final int size;
54+
55+
public RangeValue(long from, long to, long step) {
56+
super(new Value[0]);
57+
this.from = from;
58+
this.to = to;
59+
this.step = step;
60+
// x = range(0, 10, 2)
61+
// 0, 2, 4, 6, 8 | 0..10 step 2
62+
// 0, 3, 6, 9 | 0..10 step 3
63+
// 0, 4, 8 | 0..10 step 4
64+
final long base = (from < to) ? (to - from) : (from - to);
65+
final long absStep = (step < 0) ? -step : step;
66+
this.size = (int) (base / absStep + (base % absStep == 0 ? 0 : 1));
67+
}
68+
69+
@Override
70+
public Value[] getCopyElements() {
71+
final Value[] result = new Value[size];
72+
int i = 0;
73+
if (isIntegerRange()) {
74+
final int toInt = (int) to;
75+
final int stepInt = (int) step;
76+
for (int value = (int) from; value < toInt; value += stepInt) {
77+
result[i++] = NumberValue.of(value);
78+
}
79+
} else {
80+
for (long value = from; value < to; value += step) {
81+
result[i++] = NumberValue.of(value);
82+
}
83+
}
84+
return result;
85+
}
86+
87+
private boolean isIntegerRange() {
88+
if (to > 0) {
89+
return (to < Integer.MAX_VALUE) && (from > Integer.MIN_VALUE && to < Integer.MAX_VALUE);
90+
}
91+
return (to > Integer.MIN_VALUE) && (to > Integer.MIN_VALUE && from < Integer.MAX_VALUE);
92+
}
93+
94+
@Override
95+
public int size() {
96+
return size;
97+
}
98+
99+
@Override
100+
public Value get(int index) {
101+
if (isIntegerRange()) {
102+
return NumberValue.of((int) (from + index * step));
103+
}
104+
return NumberValue.of(from + (long) index * step);
105+
}
106+
107+
@Override
108+
public void set(int index, Value value) {
109+
// not implemented
110+
}
111+
112+
@Override
113+
public Object raw() {
114+
return getCopyElements();
115+
}
116+
117+
@Override
118+
public String asString() {
119+
if (size == 0) return "[]";
120+
121+
final StringBuilder sb = new StringBuilder();
122+
sb.append('[').append(from);
123+
for (long value = from + step; value < to; value += step) {
124+
sb.append(", ").append(value);
125+
}
126+
sb.append(']');
127+
return sb.toString();
128+
}
129+
130+
@Override
131+
public Iterator<Value> iterator() {
132+
if (isIntegerRange()) {
133+
final int toInt = (int) to;
134+
final int stepInt = (int) step;
135+
return new Iterator<Value>() {
136+
137+
int value = (int) from;
138+
139+
@Override
140+
public boolean hasNext() {
141+
return value < toInt;
142+
}
143+
144+
@Override
145+
public Value next() {
146+
final int result = value;
147+
value += stepInt;
148+
return NumberValue.of(result);
149+
}
150+
};
151+
}
152+
return new Iterator<Value>() {
153+
154+
long value = from;
155+
156+
@Override
157+
public boolean hasNext() {
158+
return value < to;
159+
}
160+
161+
@Override
162+
public Value next() {
163+
final long result = value;
164+
value += step;
165+
return NumberValue.of(result);
166+
}
167+
};
168+
}
169+
170+
@Override
171+
public int hashCode() {
172+
int hash = 5;
173+
hash = 59 * hash + (int) (this.from ^ (this.from >>> 32));
174+
hash = 59 * hash + (int) (this.to ^ (this.to >>> 32));
175+
hash = 59 * hash + (int) (this.step ^ (this.step >>> 32));
176+
return hash;
177+
}
178+
179+
@Override
180+
public boolean equals(Object obj) {
181+
if (this == obj) return true;
182+
if (obj == null) return false;
183+
if (getClass() != obj.getClass())
184+
return false;
185+
final RangeValue other = (RangeValue) obj;
186+
if (this.from != other.from) return false;
187+
if (this.to != other.to) return false;
188+
if (this.step != other.step) return false;
189+
return true;
190+
}
191+
192+
@Override
193+
public int compareTo(Value o) {
194+
if (o.type() == Types.ARRAY) {
195+
final int lengthCompare = Integer.compare(size(), ((ArrayValue) o).size());
196+
if (lengthCompare != 0) return lengthCompare;
197+
198+
if (o instanceof RangeValue) {
199+
final RangeValue o2 = ((RangeValue) o);
200+
int compareResult;
201+
compareResult = Long.compare(this.from, o2.from);
202+
if (compareResult != 0) return compareResult;
203+
compareResult = Long.compare(this.to, o2.to);
204+
if (compareResult != 0) return compareResult;
205+
}
206+
}
207+
return asString().compareTo(o.asString());
208+
}
209+
210+
@Override
211+
public String toString() {
212+
if (step == 1) {
213+
return String.format("range(%d, %d)", from, to);
214+
}
215+
return String.format("range(%d, %d, %d)", from, to, step);
216+
}
217+
}
218+
}

src/com/annimon/ownlang/lib/modules/std.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,6 @@ public void init() {
4747
Functions.set("arrayKeyExists", new std_arrayKeyExists());
4848
Functions.set("arrayKeys", new std_arrayKeys());
4949
Functions.set("arrayValues", new std_arrayValues());
50+
Functions.set("range", new std_range());
5051
}
5152
}

test/resources/modules/std/range.own

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use "std"
2+
use "types"
3+
use "functional"
4+
5+
def testRangeParams() {
6+
x = range(10)
7+
assertEquals(10, length(x))
8+
assertEquals(0, x[0])
9+
assertEquals(9, x[9])
10+
}
11+
12+
def testRangeParamsFromTo() {
13+
x = range(4, 10)
14+
assertEquals(6, length(x))
15+
assertEquals(4, x[0])
16+
assertEquals(9, x[5])
17+
}
18+
19+
def testRangeParamsWithStep() {
20+
x = range(4, 10, 2)
21+
assertEquals(3, length(x))
22+
assertEquals(4, x[0])
23+
assertEquals(8, x[2])
24+
}
25+
26+
def testRangeParamsReversed() {
27+
x = range(10, 4, -1)
28+
assertEquals(6, length(x))
29+
assertEquals(10, x[0])
30+
assertEquals(5, x[5])
31+
}
32+
33+
def testRangeLength() {
34+
assertEquals(10, length(range(0, 10, 1)))
35+
assertEquals(5, length(range(0, 10, 2)))
36+
assertEquals(4, length(range(0, 10, 3)))
37+
assertEquals(3, length(range(0, 10, 4)))
38+
assertEquals(2, length(range(0, 10, 5)))
39+
assertEquals(1, length(range(0, 10, 15)))
40+
}
41+
42+
def testRangeReversedLength() {
43+
assertEquals(10, length(range(10, 0, -1)))
44+
assertEquals(5, length(range(10, 0, -2)))
45+
assertEquals(4, length(range(10, 0, -3)))
46+
assertEquals(3, length(range(10, 0, -4)))
47+
assertEquals(2, length(range(10, 0, -5)))
48+
assertEquals(1, length(range(10, 0, -15)))
49+
}
50+
51+
def testRangeHuge() {
52+
x = range(-1002003004005006007, 1002003004005006007)
53+
assertEquals(-1002003004005006000, x[7])
54+
55+
x = range(-1002003004005006007, 1002003004005006007, 100000000000)
56+
assertEquals(20040061, length(x))
57+
58+
x = range(-10000000, 20000000)
59+
assertEquals(30000000, length(x))
60+
assertEquals(0, x[10000000])
61+
}
62+
63+
def testRangeAsString() {
64+
x = range(1, 6)
65+
assertEquals("[1, 2, 3, 4, 5]", string(x))
66+
67+
x = range(1, 6, 2)
68+
assertEquals("[1, 3, 5]", string(x))
69+
assertEquals(string([1,3,5]), string(x))
70+
}
71+
72+
def testRangeIterate() {
73+
sum = 0
74+
for x : range(5) {
75+
sum += x
76+
}
77+
assertEquals(10, sum)
78+
}
79+
80+
def testRangeFunctionalForeach() {
81+
i = 0
82+
foreach(range(5), def(x) = assertEquals(i++, x))
83+
}
84+
85+
def testRangeFunctionalReduce() {
86+
sum = reduce(range(5), 0, def(x, y) = x + y)
87+
assertEquals(10, sum)
88+
}
89+
90+
def testRangeInvalid() {
91+
assertEquals(0, length(range(-100)))
92+
assertEquals(0, length(range(0, -100, 1)))
93+
assertEquals(0, length(range(0, 100, 0)))
94+
}

0 commit comments

Comments
 (0)