1
|
|
|
2
|
|
|
3
|
|
|
4
|
|
|
5
|
|
|
6
|
|
|
7
|
|
|
8
|
|
|
9
|
|
|
10
|
|
|
11
|
|
|
12
|
|
|
13
|
|
|
14
|
|
|
15
|
|
|
16
|
|
|
17
|
|
|
18
|
|
|
19
|
|
|
20
|
|
|
21
|
|
|
22
|
|
|
23
|
|
|
24
|
|
|
25
|
|
|
26
|
|
|
27
|
|
|
28
|
|
|
29
|
|
|
30
|
|
|
31
|
|
|
32
|
|
|
33
|
|
|
34
|
|
|
35
|
|
|
36
|
|
|
37
|
|
|
38
|
|
|
39
|
|
|
40
|
|
|
41
|
|
|
42
|
|
|
43
|
|
|
44
|
|
|
45
|
|
|
46
|
|
package groovy.lang;
|
47
|
|
|
48
|
|
import java.util.AbstractList;
|
49
|
|
import java.util.Iterator;
|
50
|
|
import java.util.List;
|
51
|
|
|
52
|
|
import org.codehaus.groovy.runtime.InvokerHelper;
|
53
|
|
import org.codehaus.groovy.runtime.IteratorClosureAdapter;
|
54
|
|
|
55
|
|
|
56
|
|
|
57
|
|
|
58
|
|
|
59
|
|
|
60
|
|
|
61
|
|
|
62
|
|
public class ObjectRange extends AbstractList implements Range {
|
63
|
|
|
64
|
|
private Comparable from;
|
65
|
|
private Comparable to;
|
66
|
|
private int size = -1;
|
67
|
|
private final boolean reverse;
|
68
|
|
|
69
|
0
|
public ObjectRange(Comparable from, Comparable to) {
|
70
|
0
|
this.reverse = InvokerHelper.compareGreaterThan(from, to);
|
71
|
0
|
if (this.reverse) {
|
72
|
0
|
constructorHelper(to, from);
|
73
|
|
} else {
|
74
|
0
|
constructorHelper(from, to);
|
75
|
|
}
|
76
|
|
}
|
77
|
|
|
78
|
0
|
public ObjectRange(Comparable from, Comparable to, boolean reverse) {
|
79
|
0
|
constructorHelper(from, to);
|
80
|
|
|
81
|
0
|
this.reverse = reverse;
|
82
|
|
}
|
83
|
|
|
84
|
0
|
private void constructorHelper(Comparable from, Comparable to) {
|
85
|
0
|
if (from == null) {
|
86
|
0
|
throw new IllegalArgumentException("Must specify a non-null value for the 'from' index in a Range");
|
87
|
|
}
|
88
|
0
|
if (to == null) {
|
89
|
0
|
throw new IllegalArgumentException("Must specify a non-null value for the 'to' index in a Range");
|
90
|
|
}
|
91
|
0
|
if (from.getClass() == to.getClass()) {
|
92
|
0
|
this.from = from;
|
93
|
0
|
this.to = to;
|
94
|
|
} else {
|
95
|
0
|
this.from = normaliseType(from);
|
96
|
0
|
this.to = normaliseType(to);
|
97
|
|
}
|
98
|
|
}
|
99
|
|
|
100
|
0
|
public int hashCode() {
|
101
|
|
|
102
|
0
|
return from.hashCode() ^ to.hashCode() + (reverse ? 1 : 0);
|
103
|
|
}
|
104
|
|
|
105
|
0
|
public boolean equals(Object that) {
|
106
|
0
|
if (that instanceof ObjectRange) {
|
107
|
0
|
return equals((ObjectRange) that);
|
108
|
|
}
|
109
|
0
|
else if (that instanceof List) {
|
110
|
0
|
return equals((List) that);
|
111
|
|
}
|
112
|
0
|
return false;
|
113
|
|
}
|
114
|
|
|
115
|
0
|
public boolean equals(ObjectRange that) {
|
116
|
0
|
return this.reverse == that.reverse
|
117
|
|
&& InvokerHelper.compareEqual(this.from, that.from)
|
118
|
|
&& InvokerHelper.compareEqual(this.to, that.to);
|
119
|
|
}
|
120
|
|
|
121
|
0
|
public boolean equals(List that) {
|
122
|
0
|
int size = size();
|
123
|
0
|
if (that.size() == size) {
|
124
|
0
|
for (int i = 0; i < size; i++) {
|
125
|
0
|
if (!InvokerHelper.compareEqual(get(i), that.get(i))) {
|
126
|
0
|
return false;
|
127
|
|
}
|
128
|
|
}
|
129
|
0
|
return true;
|
130
|
|
}
|
131
|
0
|
return false;
|
132
|
|
}
|
133
|
|
|
134
|
0
|
public Comparable getFrom() {
|
135
|
0
|
return from;
|
136
|
|
}
|
137
|
|
|
138
|
0
|
public Comparable getTo() {
|
139
|
0
|
return to;
|
140
|
|
}
|
141
|
|
|
142
|
0
|
public boolean isReverse() {
|
143
|
0
|
return reverse;
|
144
|
|
}
|
145
|
|
|
146
|
0
|
public Object get(int index) {
|
147
|
0
|
if (index < 0) {
|
148
|
0
|
throw new IndexOutOfBoundsException("Index: " + index + " should not be negative");
|
149
|
|
}
|
150
|
0
|
if (index >= size()) {
|
151
|
0
|
throw new IndexOutOfBoundsException("Index: " + index + " is too big for range: " + this);
|
152
|
|
}
|
153
|
0
|
Object value = null;
|
154
|
0
|
if (reverse) {
|
155
|
0
|
value = to;
|
156
|
0
|
System.out.println("get(" + index + ")");
|
157
|
|
|
158
|
0
|
for (int i = 0; i < index; i++) {
|
159
|
0
|
System.out.println("decrement: " + i + " value: " + value);
|
160
|
0
|
value = decrement(value);
|
161
|
|
}
|
162
|
|
}
|
163
|
|
else {
|
164
|
0
|
value = from;
|
165
|
0
|
for (int i = 0; i < index; i++) {
|
166
|
0
|
value = increment(value);
|
167
|
|
}
|
168
|
|
}
|
169
|
0
|
return value;
|
170
|
|
}
|
171
|
|
|
172
|
0
|
public Iterator iterator() {
|
173
|
0
|
return new Iterator() {
|
174
|
|
int index = 0;
|
175
|
0
|
Object value = (reverse) ? to : from;
|
176
|
|
|
177
|
0
|
public boolean hasNext() {
|
178
|
0
|
return index < size();
|
179
|
|
}
|
180
|
|
|
181
|
0
|
public Object next() {
|
182
|
0
|
if (index++ > 0) {
|
183
|
0
|
if (index > size()) {
|
184
|
0
|
value = null;
|
185
|
|
}
|
186
|
|
else {
|
187
|
0
|
if (reverse) {
|
188
|
0
|
value = decrement(value);
|
189
|
|
}
|
190
|
|
else {
|
191
|
0
|
value = increment(value);
|
192
|
|
}
|
193
|
|
}
|
194
|
|
}
|
195
|
0
|
return value;
|
196
|
|
}
|
197
|
|
|
198
|
0
|
public void remove() {
|
199
|
0
|
ObjectRange.this.remove(index);
|
200
|
|
}
|
201
|
|
};
|
202
|
|
}
|
203
|
|
|
204
|
0
|
public int size() {
|
205
|
0
|
if (size == -1) {
|
206
|
|
|
207
|
0
|
size = 0;
|
208
|
0
|
Object value = from;
|
209
|
0
|
while (to.compareTo(value) >= 0) {
|
210
|
0
|
value = increment(value);
|
211
|
0
|
size++;
|
212
|
|
}
|
213
|
|
}
|
214
|
0
|
return size;
|
215
|
|
}
|
216
|
|
|
217
|
0
|
public List subList(int fromIndex, int toIndex) {
|
218
|
0
|
if (fromIndex < 0) {
|
219
|
0
|
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
|
220
|
|
}
|
221
|
0
|
int size = size();
|
222
|
0
|
if (toIndex > size) {
|
223
|
0
|
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
|
224
|
|
}
|
225
|
0
|
if (fromIndex > toIndex) {
|
226
|
0
|
throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
|
227
|
|
}
|
228
|
0
|
if (--toIndex >= size) {
|
229
|
0
|
return new ObjectRange((Comparable) get(fromIndex), getTo(), reverse);
|
230
|
|
}
|
231
|
|
else {
|
232
|
0
|
return new ObjectRange((Comparable) get(fromIndex), (Comparable) get(toIndex), reverse);
|
233
|
|
}
|
234
|
|
}
|
235
|
|
|
236
|
0
|
public String toString() {
|
237
|
0
|
return (reverse) ? "" + to + ".." + from : "" + from + ".." + to;
|
238
|
|
}
|
239
|
|
|
240
|
0
|
public String inspect() {
|
241
|
0
|
String toText = InvokerHelper.inspect(to);
|
242
|
0
|
String fromText = InvokerHelper.inspect(from);
|
243
|
0
|
return (reverse) ? "" + toText + ".." + fromText : "" + fromText + ".." + toText;
|
244
|
|
}
|
245
|
|
|
246
|
0
|
public boolean contains(Comparable value) {
|
247
|
0
|
int result = from.compareTo(value);
|
248
|
0
|
if (result == 0) {
|
249
|
0
|
return true;
|
250
|
|
}
|
251
|
0
|
return result < 0 && to.compareTo(value) >= 0;
|
252
|
|
}
|
253
|
|
|
254
|
0
|
public void step(int step, Closure closure) {
|
255
|
0
|
if (reverse) {
|
256
|
0
|
step = -step;
|
257
|
|
}
|
258
|
0
|
if (step >= 0) {
|
259
|
0
|
Comparable value = from;
|
260
|
0
|
while (value.compareTo(to) <= 0) {
|
261
|
0
|
closure.call(value);
|
262
|
0
|
for (int i = 0; i < step; i++) {
|
263
|
0
|
value = (Comparable) increment(value);
|
264
|
|
}
|
265
|
|
}
|
266
|
|
}
|
267
|
|
else {
|
268
|
0
|
step = -step;
|
269
|
0
|
Comparable value = to;
|
270
|
0
|
while (value.compareTo(from) >= 0) {
|
271
|
0
|
closure.call(value);
|
272
|
0
|
for (int i = 0; i < step; i++) {
|
273
|
0
|
value = (Comparable) decrement(value);
|
274
|
|
}
|
275
|
|
}
|
276
|
|
}
|
277
|
|
}
|
278
|
|
|
279
|
0
|
public List step(int step) {
|
280
|
0
|
IteratorClosureAdapter adapter = new IteratorClosureAdapter(this);
|
281
|
0
|
step(step, adapter);
|
282
|
0
|
return adapter.asList();
|
283
|
|
}
|
284
|
|
|
285
|
0
|
protected Object increment(Object value) {
|
286
|
0
|
return InvokerHelper.invokeMethod(value, "next", null);
|
287
|
|
}
|
288
|
|
|
289
|
0
|
protected Object decrement(Object value) {
|
290
|
0
|
return InvokerHelper.invokeMethod(value, "previous", null);
|
291
|
|
}
|
292
|
|
|
293
|
0
|
private static Comparable normaliseType(final Comparable operand) {
|
294
|
0
|
if (operand instanceof Character) {
|
295
|
0
|
return new Integer(((Character)operand).charValue());
|
296
|
0
|
} else if (operand instanceof String) {
|
297
|
0
|
final String string = (String)operand;
|
298
|
|
|
299
|
0
|
if (string.length() == 1)
|
300
|
0
|
return new Integer(string.charAt(0));
|
301
|
|
else
|
302
|
0
|
return string;
|
303
|
|
} else {
|
304
|
0
|
return operand;
|
305
|
|
}
|
306
|
|
}
|
307
|
|
}
|
308
|
|
|