1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.functor.generator.range;
19
20 import java.util.Collection;
21
22 import org.apache.commons.functor.BinaryFunction;
23 import org.apache.commons.functor.UnaryProcedure;
24 import org.apache.commons.functor.generator.loop.LoopGenerator;
25 import org.apache.commons.lang3.Validate;
26
27
28
29
30
31
32
33 public final class CharacterRange extends LoopGenerator<Character> implements Range<Character, Integer> {
34
35
36
37
38
39
40 public static final BoundType DEFAULT_LEFT_BOUND_TYPE = BoundType.CLOSED;
41
42
43
44
45 public static final BoundType DEFAULT_RIGHT_BOUND_TYPE = BoundType.CLOSED;
46
47
48
49
50 private final Endpoint<Character> leftEndpoint;
51
52
53
54
55 private final Endpoint<Character> rightEndpoint;
56
57
58
59
60 private final int step;
61
62
63
64
65 public static final BinaryFunction<Character, Character, Integer> DEFAULT_STEP
66 = new BinaryFunction<Character, Character, Integer>() {
67
68 public Integer evaluate(Character left, Character right) {
69 return left > right ? -1 : 1;
70 }
71 };
72
73
74
75
76
77
78
79
80
81 public CharacterRange(char from, char to) {
82 this(from, to, DEFAULT_STEP.evaluate(from, to).intValue());
83 }
84
85
86
87
88
89
90
91
92 public CharacterRange(char from, char to, int step) {
93 this(from, BoundType.CLOSED, to, BoundType.CLOSED, step);
94 }
95
96
97
98
99
100
101
102
103
104
105 public CharacterRange(char from, BoundType leftBoundType, char to,
106 BoundType rightBoundType, int step) {
107 this.leftEndpoint = Validate
108 .notNull(new Endpoint<Character>(from, leftBoundType),
109 "Left Endpoint argument must not be null");
110 this.rightEndpoint = Validate
111 .notNull(new Endpoint<Character>(to, rightBoundType),
112 "Right Endpoint argument must not be null");
113 this.step = step;
114 if (from != to && Integer.signum(step) != Integer.signum(to - from)) {
115 throw new IllegalArgumentException("Will never reach " + to
116 + " from " + from
117 + " using step " + step);
118 }
119 }
120
121
122
123
124
125
126
127
128 public CharacterRange(Endpoint<Character> from, Endpoint<Character> to,
129 int step) {
130 this.leftEndpoint = Validate
131 .notNull(from, "Left Endpoint argument must not be null");
132 this.rightEndpoint = Validate
133 .notNull(to, "Right Endpoint argument must not be null");
134 this.step = step;
135 if (from != to
136 && Integer.signum(step) != Integer.signum(to.getValue()
137 - from.getValue())) {
138 throw new IllegalArgumentException("Will never reach " + to
139 + " from " + from
140 + " using step " + step);
141 }
142 }
143
144
145
146
147
148
149 public Endpoint<Character> getLeftEndpoint() {
150 return this.leftEndpoint;
151 }
152
153
154
155
156 public Endpoint<Character> getRightEndpoint() {
157 return this.rightEndpoint;
158 }
159
160
161
162
163 public Integer getStep() {
164 return this.step;
165 }
166
167
168
169
170 public void run(UnaryProcedure<? super Character> proc) {
171 final int step = this.getStep();
172 final boolean includeLeftValue = this.getLeftEndpoint()
173 .getBoundType() == BoundType.CLOSED;
174 final boolean includeRightValue = this.getRightEndpoint()
175 .getBoundType() == BoundType.CLOSED;
176 final char leftValue = this.getLeftEndpoint().getValue();
177 final char rightValue = this.getRightEndpoint().getValue();
178 if (step < 0) {
179 final char from = (char) (includeLeftValue ? leftValue : leftValue
180 + step);
181 if (includeRightValue) {
182 for (char i = from; i >= rightValue; i += step) {
183 proc.run(i);
184 }
185 } else {
186 for (char i = from; i > rightValue; i += step) {
187 proc.run(i);
188 }
189 }
190 } else {
191 final char from = (char) (includeLeftValue ? this
192 .getLeftEndpoint().getValue() : (this.getLeftEndpoint()
193 .getValue() + step));
194 if (includeRightValue) {
195 for (char i = from; i <= rightValue; i += step) {
196 proc.run(i);
197 }
198 } else {
199 for (char i = from; i < rightValue; i += step) {
200 proc.run(i);
201 }
202 }
203 }
204 }
205
206
207
208
209 @Override
210 public String toString() {
211 return "CharacterRange<" + this.leftEndpoint.toLeftString() + ", "
212 + this.rightEndpoint.toRightString() + ", " + step + ">";
213 }
214
215
216
217
218 @Override
219 public boolean equals(Object obj) {
220 if (obj == this) {
221 return true;
222 }
223 if (!(obj instanceof CharacterRange)) {
224 return false;
225 }
226 CharacterRange that = (CharacterRange) obj;
227 return this.leftEndpoint.equals(that.leftEndpoint)
228 && this.rightEndpoint.equals(that.rightEndpoint)
229 && this.step == that.step;
230 }
231
232
233
234
235 @Override
236 public int hashCode() {
237 int hash = "CharacterRange".hashCode();
238 hash <<= 2;
239 hash ^= this.leftEndpoint.getValue();
240 hash <<= 2;
241 hash ^= this.rightEndpoint.getValue();
242 hash <<= 2;
243 hash ^= this.step;
244 return hash;
245 }
246
247
248
249
250 public boolean isEmpty() {
251 double leftValue = this.getLeftEndpoint().getValue().charValue();
252 double rightValue = this.getRightEndpoint().getValue().charValue();
253 boolean closedLeft = this.getLeftEndpoint().getBoundType() == BoundType.CLOSED;
254 boolean closedRight = this.getRightEndpoint().getBoundType() == BoundType.CLOSED;
255 if (!closedLeft && !closedRight
256 && this.getLeftEndpoint().equals(this.getRightEndpoint())) {
257 return Boolean.TRUE;
258 }
259 double step = this.getStep().intValue();
260 if (step > 0.0) {
261 double firstValue = closedLeft ? leftValue : leftValue + step;
262 return closedRight ? firstValue > rightValue
263 : firstValue >= rightValue;
264 } else {
265 double firstValue = closedLeft ? leftValue : leftValue + step;
266 return closedRight ? firstValue < rightValue
267 : firstValue <= rightValue;
268 }
269 }
270
271
272
273
274 public boolean contains(Character obj) {
275 if (obj == null) {
276 return Boolean.FALSE;
277 }
278 char leftValue = this.getLeftEndpoint().getValue().charValue();
279 char rightValue = this.getRightEndpoint().getValue().charValue();
280 boolean includeLeft = this.getLeftEndpoint().getBoundType() == BoundType.CLOSED;
281 boolean includeRight = this.getRightEndpoint().getBoundType() == BoundType.CLOSED;
282 int step = this.getStep().intValue();
283 int value = (int) obj.charValue();
284
285 int firstValue = 0;
286 int lastValue = 0;
287
288 if (step < 0.0) {
289 firstValue = includeLeft ? leftValue : leftValue + step;
290 lastValue = includeRight ? rightValue : rightValue + 1;
291 if (value > firstValue || value < lastValue) {
292 return Boolean.FALSE;
293 }
294 } else {
295 firstValue = includeLeft ? leftValue : leftValue + step;
296 lastValue = includeRight ? rightValue : rightValue - 1;
297 if (value < firstValue || value > lastValue) {
298 return Boolean.FALSE;
299 }
300 }
301 return ((double) (value - firstValue) / step + 1) % 1.0 == 0.0;
302 }
303
304
305
306
307 public boolean containsAll(Collection<Character> col) {
308 if (col == null || col.size() == 0) {
309 return Boolean.FALSE;
310 }
311 boolean r = Boolean.TRUE;
312 for (Character t : col) {
313 if (!this.contains(t)) {
314 r = Boolean.FALSE;
315 break;
316 }
317 }
318 return r;
319 }
320
321 }