1: package de.luschny.math.util;
2:
3: /**
4: * A PositiveRange is an interval of integers, given by a lower bound L and an
5: * upper bound U, such that 0 <= L and L <= U. A PositiveRange is immutable.
6: */
7:
8: public final class PositiveRange implements Cloneable
9: {
10:
11: private final int min;
12: private final int max;
13:
14: /**
15: * Creates a PositiveRange, i.e. a range of integers, such that 0 <= low <=
16: * high.
17: *
18: * @param low
19: * The low bound (minimum) of the range.
20: * @param high
21: * The high bound (maximum) of the range.
22: * @throws IllegalArgumentException
23: */
24:
25: public PositiveRange(final int low, final int high)
26: {
27: if (!(0 <= low && low <= high))
28: {
29: // Yes, we force the arguments to be ordered
30: // to make the calling code more readable.
31: throw new IllegalArgumentException(new StringBuffer(64).append("The condition 0 <= ").append(low).append(
32: " <= ").append(high).append(" is false.").toString());
33: }
34:
35: this.min = low;
36: this.max = high;
37: }
38:
39: /**
40: * Creates and returns a copy of this object.
41: *
42: * @return A copy of this PositiveRange.
43: */
44:
45: @Override
46: public Object clone()
47: {
48: try
49: {
50: return super.clone();
51: }
52: catch (CloneNotSupportedException e)
53: {
54: throw new InternalError(e.toString());
55: }
56: }
57:
58: /**
59: * Get the lower bound (minimum) of the range.
60: *
61: * @return The minimum of the range.
62: */
63:
64: public int getMin()
65: {
66: return min;
67: }
68:
69: /**
70: * Get upper bound (maximum) of the range.
71: *
72: * @return The maximum of the range.
73: */
74:
75: public int getMax()
76: {
77: return max;
78: }
79:
80: /**
81: * <p>
82: * Gets the range as a <code>String</code>.
83: * </p>
84: * <p>
85: * The format of the String is '[min, max]'.
86: * </p>
87: *
88: * @return the <code>String</code> representation of this range.
89: */
90:
91: @Override
92: public String toString()
93: {
94: return new StringBuffer(32).append('[').append(min).append(',').append(max).append(']').toString();
95: }
96:
97: /**
98: * Checks, if the given value lies within the range, i.e. min <= value
99: * and value <= max.
100: *
101: * @param value
102: * The value to checked.
103: * @return True, if the range includes the value, false otherwise.
104: * @see PositiveRange#containsOrFail(int value)
105: */
106:
107: public boolean contains(final int value)
108: {
109: return min <= value && value <= max;
110: }
111:
112: /**
113: * Checks, if the given value lies within the range, i.e. min <= value
114: * and value <= max. If the value is not contained an
115: * IndexOutOfBoundsException will be raised.
116: *
117: * @param value
118: * The value to checked.
119: * @return True, if the range includes the value, false otherwise.
120: * @throws IndexOutOfBoundsException
121: */
122:
123: public boolean containsOrFail(final int value)
124: {
125: if (!(min <= value && value <= max))
126: {
127: throw new IndexOutOfBoundsException(new StringBuffer(64).append(this.toString()).append(
128: " does not contain ").append(value).toString());
129: }
130: return true;
131: }
132:
133: /**
134: * Checks, if the given range is a subrange, i.e. this.min <= range.min
135: * and range.max <= this.max.
136: *
137: * @param range
138: * The range to be checked.
139: * @return True, if the given range lies within this range, false otherwise.
140: * @see PositiveRange#containsOrFail(PositiveRange range)
141: */
142:
143: public boolean contains(final PositiveRange range)
144: {
145: return min <= range.min && range.max <= max;
146: }
147:
148: /**
149: * Checks, if the given range is a subrange, i.e. this.min <= range.min
150: * and range.max <= this.max. If the range is not contained an
151: * IndexOutOfBoundsException will be raised.
152: *
153: * @param range
154: * The range to be checked.
155: * @return True, if the given range lies within this range, otherwise an
156: * IndexOutOfBoundsException is thrown.
157: * @throws IndexOutOfBoundsException
158: */
159:
160: public boolean containsOrFail(final PositiveRange range)
161: {
162: if (!(min <= range.min && range.max <= max))
163: {
164: throw new IndexOutOfBoundsException(new StringBuffer(64).append(this.toString()).append(
165: " does not contain ").append(range.toString()).toString());
166: }
167: return true;
168: }
169:
170: /**
171: * Computes the size of the range.
172: *
173: * @return The size of the range.
174: */
175:
176: public int size()
177: {
178: return max - min + 1;
179: }
180:
181: /**
182: * Compares this range to the specified object. The result is true if and
183: * only if the argument is not null and is an range object that has the same
184: * bound values as this object.
185: *
186: * @param o
187: * The object to compare with.
188: * @return True if the objects are the same; false otherwise.
189: */
190:
191: @Override
192: public boolean equals(Object o)
193: {
194: if (this == o)
195: {
196: return true;
197: }
198: if (!(o instanceof PositiveRange))
199: {
200: return false;
201: }
202:
203: PositiveRange positiveRange = (PositiveRange) o;
204:
205: if (max != positiveRange.max)
206: {
207: return false;
208: }
209: return min == positiveRange.min;
210:
211: }
212:
213: /**
214: * A hash code value for this range.
215: *
216: * @return Returns a hash code for this.
217: */
218:
219: @Override
220: public int hashCode()
221: {
222: return 29 * min + max;
223: }
224: }