1 | /* |
2 | * Copyright 2001-2005 Stephen Colebourne |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | package org.joda.time.field; |
17 | |
18 | import org.joda.time.DateTimeField; |
19 | import org.joda.time.DateTimeFieldType; |
20 | import org.joda.time.IllegalFieldValueException; |
21 | |
22 | /** |
23 | * General utilities that don't fit elsewhere. |
24 | * <p> |
25 | * FieldUtils is thread-safe and immutable. |
26 | * |
27 | * @author Stephen Colebourne |
28 | * @since 1.0 |
29 | */ |
30 | public class FieldUtils { |
31 | |
32 | /** |
33 | * Restricted constructor. |
34 | */ |
35 | private FieldUtils() { |
36 | super(); |
37 | } |
38 | |
39 | //------------------------------------------------------------------------ |
40 | /** |
41 | * Negates the input throwing an exception if it can't negate it. |
42 | * |
43 | * @param value the value to negate |
44 | * @return the negated value |
45 | * @throws ArithmeticException if the value is Integer.MIN_VALUE |
46 | * @since 1.1 |
47 | */ |
48 | public static int safeNegate(int value) { |
49 | if (value == Integer.MIN_VALUE) { |
50 | throw new ArithmeticException("Integer.MIN_VALUE cannot be negated"); |
51 | } |
52 | return -value; |
53 | } |
54 | |
55 | /** |
56 | * Add two values throwing an exception if overflow occurs. |
57 | * |
58 | * @param val1 the first value |
59 | * @param val2 the second value |
60 | * @return the new total |
61 | * @throws ArithmeticException if the value is too big or too small |
62 | */ |
63 | public static int safeAdd(int val1, int val2) { |
64 | int sum = val1 + val2; |
65 | // If there is a sign change, but the two values have the same sign... |
66 | if ((val1 ^ sum) < 0 && (val1 ^ val2) >= 0) { |
67 | throw new ArithmeticException |
68 | ("The calculation caused an overflow: " + val1 + " + " + val2); |
69 | } |
70 | return sum; |
71 | } |
72 | |
73 | /** |
74 | * Add two values throwing an exception if overflow occurs. |
75 | * |
76 | * @param val1 the first value |
77 | * @param val2 the second value |
78 | * @return the new total |
79 | * @throws ArithmeticException if the value is too big or too small |
80 | */ |
81 | public static long safeAdd(long val1, long val2) { |
82 | long sum = val1 + val2; |
83 | // If there is a sign change, but the two values have the same sign... |
84 | if ((val1 ^ sum) < 0 && (val1 ^ val2) >= 0) { |
85 | throw new ArithmeticException |
86 | ("The calculation caused an overflow: " + val1 + " + " + val2); |
87 | } |
88 | return sum; |
89 | } |
90 | |
91 | /** |
92 | * Subtracts two values throwing an exception if overflow occurs. |
93 | * |
94 | * @param val1 the first value, to be taken away from |
95 | * @param val2 the second value, the amount to take away |
96 | * @return the new total |
97 | * @throws ArithmeticException if the value is too big or too small |
98 | */ |
99 | public static long safeSubtract(long val1, long val2) { |
100 | long diff = val1 - val2; |
101 | // If there is a sign change, but the two values have different signs... |
102 | if ((val1 ^ diff) < 0 && (val1 ^ val2) < 0) { |
103 | throw new ArithmeticException |
104 | ("The calculation caused an overflow: " + val1 + " - " + val2); |
105 | } |
106 | return diff; |
107 | } |
108 | |
109 | /** |
110 | * Multiply two values throwing an exception if overflow occurs. |
111 | * |
112 | * @param val1 the first value |
113 | * @param val2 the second value |
114 | * @return the new total |
115 | * @throws ArithmeticException if the value is too big or too small |
116 | * @since 1.2 |
117 | */ |
118 | public static int safeMultiply(int val1, int val2) { |
119 | long total = (long) val1 * (long) val2; |
120 | if (total < Integer.MIN_VALUE || total > Integer.MAX_VALUE) { |
121 | throw new ArithmeticException |
122 | ("The calculation caused an overflow: " + val1 + " * " + val2); |
123 | } |
124 | return (int) total; |
125 | } |
126 | |
127 | /** |
128 | * Multiply two values throwing an exception if overflow occurs. |
129 | * |
130 | * @param val1 the first value |
131 | * @param scalar the second value |
132 | * @return the new total |
133 | * @throws ArithmeticException if the value is too big or too small |
134 | * @since 1.2 |
135 | */ |
136 | public static long safeMultiply(long val1, int scalar) { |
137 | switch (scalar) { |
138 | case -1: |
139 | return -val1; |
140 | case 0: |
141 | return 0L; |
142 | case 1: |
143 | return val1; |
144 | } |
145 | long total = val1 * scalar; |
146 | if (total / scalar != val1) { |
147 | throw new ArithmeticException |
148 | ("The calculation caused an overflow: " + val1 + " * " + scalar); |
149 | } |
150 | return total; |
151 | } |
152 | |
153 | /** |
154 | * Multiply two values throwing an exception if overflow occurs. |
155 | * |
156 | * @param val1 the first value |
157 | * @param val2 the second value |
158 | * @return the new total |
159 | * @throws ArithmeticException if the value is too big or too small |
160 | */ |
161 | public static long safeMultiply(long val1, long val2) { |
162 | if (val2 == 1) { |
163 | return val1; |
164 | } |
165 | if (val2 == 0) { |
166 | return 0; |
167 | } |
168 | long total = val1 * val2; |
169 | if (total / val2 != val1) { |
170 | throw new ArithmeticException |
171 | ("The calculation caused an overflow: " + val1 + " * " + val2); |
172 | } |
173 | return total; |
174 | } |
175 | |
176 | /** |
177 | * Casts to an int throwing an exception if overflow occurs. |
178 | * |
179 | * @param value the value |
180 | * @return the value as an int |
181 | * @throws ArithmeticException if the value is too big or too small |
182 | */ |
183 | public static int safeToInt(long value) { |
184 | if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) { |
185 | return (int) value; |
186 | } |
187 | throw new ArithmeticException("Value cannot fit in an int: " + value); |
188 | } |
189 | |
190 | /** |
191 | * Multiply two values to return an int throwing an exception if overflow occurs. |
192 | * |
193 | * @param val1 the first value |
194 | * @param val2 the second value |
195 | * @return the new total |
196 | * @throws ArithmeticException if the value is too big or too small |
197 | */ |
198 | public static int safeMultiplyToInt(long val1, long val2) { |
199 | long val = FieldUtils.safeMultiply(val1, val2); |
200 | return FieldUtils.safeToInt(val); |
201 | } |
202 | |
203 | //----------------------------------------------------------------------- |
204 | /** |
205 | * Verify that input values are within specified bounds. |
206 | * |
207 | * @param value the value to check |
208 | * @param lowerBound the lower bound allowed for value |
209 | * @param upperBound the upper bound allowed for value |
210 | * @throws IllegalFieldValueException if value is not in the specified bounds |
211 | */ |
212 | public static void verifyValueBounds(DateTimeField field, |
213 | int value, int lowerBound, int upperBound) { |
214 | if ((value < lowerBound) || (value > upperBound)) { |
215 | throw new IllegalFieldValueException |
216 | (field.getType(), new Integer(value), |
217 | new Integer(lowerBound), new Integer(upperBound)); |
218 | } |
219 | } |
220 | |
221 | /** |
222 | * Verify that input values are within specified bounds. |
223 | * |
224 | * @param value the value to check |
225 | * @param lowerBound the lower bound allowed for value |
226 | * @param upperBound the upper bound allowed for value |
227 | * @throws IllegalFieldValueException if value is not in the specified bounds |
228 | * @since 1.1 |
229 | */ |
230 | public static void verifyValueBounds(DateTimeFieldType fieldType, |
231 | int value, int lowerBound, int upperBound) { |
232 | if ((value < lowerBound) || (value > upperBound)) { |
233 | throw new IllegalFieldValueException |
234 | (fieldType, new Integer(value), |
235 | new Integer(lowerBound), new Integer(upperBound)); |
236 | } |
237 | } |
238 | |
239 | /** |
240 | * Verify that input values are within specified bounds. |
241 | * |
242 | * @param value the value to check |
243 | * @param lowerBound the lower bound allowed for value |
244 | * @param upperBound the upper bound allowed for value |
245 | * @throws IllegalFieldValueException if value is not in the specified bounds |
246 | */ |
247 | public static void verifyValueBounds(String fieldName, |
248 | int value, int lowerBound, int upperBound) { |
249 | if ((value < lowerBound) || (value > upperBound)) { |
250 | throw new IllegalFieldValueException |
251 | (fieldName, new Integer(value), |
252 | new Integer(lowerBound), new Integer(upperBound)); |
253 | } |
254 | } |
255 | |
256 | /** |
257 | * Utility method used by addWrapField implementations to ensure the new |
258 | * value lies within the field's legal value range. |
259 | * |
260 | * @param currentValue the current value of the data, which may lie outside |
261 | * the wrapped value range |
262 | * @param wrapValue the value to add to current value before |
263 | * wrapping. This may be negative. |
264 | * @param minValue the wrap range minimum value. |
265 | * @param maxValue the wrap range maximum value. This must be |
266 | * greater than minValue (checked by the method). |
267 | * @return the wrapped value |
268 | * @throws IllegalArgumentException if minValue is greater |
269 | * than or equal to maxValue |
270 | */ |
271 | public static int getWrappedValue(int currentValue, int wrapValue, |
272 | int minValue, int maxValue) { |
273 | return getWrappedValue(currentValue + wrapValue, minValue, maxValue); |
274 | } |
275 | |
276 | /** |
277 | * Utility method that ensures the given value lies within the field's |
278 | * legal value range. |
279 | * |
280 | * @param value the value to fit into the wrapped value range |
281 | * @param minValue the wrap range minimum value. |
282 | * @param maxValue the wrap range maximum value. This must be |
283 | * greater than minValue (checked by the method). |
284 | * @return the wrapped value |
285 | * @throws IllegalArgumentException if minValue is greater |
286 | * than or equal to maxValue |
287 | */ |
288 | public static int getWrappedValue(int value, int minValue, int maxValue) { |
289 | if (minValue >= maxValue) { |
290 | throw new IllegalArgumentException("MIN > MAX"); |
291 | } |
292 | |
293 | int wrapRange = maxValue - minValue + 1; |
294 | value -= minValue; |
295 | |
296 | if (value >= 0) { |
297 | return (value % wrapRange) + minValue; |
298 | } |
299 | |
300 | int remByRange = (-value) % wrapRange; |
301 | |
302 | if (remByRange == 0) { |
303 | return 0 + minValue; |
304 | } |
305 | return (wrapRange - remByRange) + minValue; |
306 | } |
307 | |
308 | //----------------------------------------------------------------------- |
309 | /** |
310 | * Compares two objects as equals handling null. |
311 | * |
312 | * @param object1 the first object |
313 | * @param object2 the second object |
314 | * @return true if equal |
315 | * @since 1.4 |
316 | */ |
317 | public static boolean equals(Object object1, Object object2) { |
318 | if (object1 == object2) { |
319 | return true; |
320 | } |
321 | if (object1 == null || object2 == null) { |
322 | return false; |
323 | } |
324 | return object1.equals(object2); |
325 | } |
326 | |
327 | } |