001 /*
002 * Copyright 2001-2005 Stephen Colebourne
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.joda.time.field;
017
018 import org.joda.time.DateTimeField;
019 import org.joda.time.DateTimeFieldType;
020 import org.joda.time.IllegalFieldValueException;
021
022 /**
023 * General utilities that don't fit elsewhere.
024 * <p>
025 * FieldUtils is thread-safe and immutable.
026 *
027 * @author Stephen Colebourne
028 * @since 1.0
029 */
030 public class FieldUtils {
031
032 /**
033 * Restricted constructor.
034 */
035 private FieldUtils() {
036 super();
037 }
038
039 //------------------------------------------------------------------------
040 /**
041 * Negates the input throwing an exception if it can't negate it.
042 *
043 * @param value the value to negate
044 * @return the negated value
045 * @throws ArithmeticException if the value is Integer.MIN_VALUE
046 * @since 1.1
047 */
048 public static int safeNegate(int value) {
049 if (value == Integer.MIN_VALUE) {
050 throw new ArithmeticException("Integer.MIN_VALUE cannot be negated");
051 }
052 return -value;
053 }
054
055 /**
056 * Add two values throwing an exception if overflow occurs.
057 *
058 * @param val1 the first value
059 * @param val2 the second value
060 * @return the new total
061 * @throws ArithmeticException if the value is too big or too small
062 */
063 public static int safeAdd(int val1, int val2) {
064 int sum = val1 + val2;
065 // If there is a sign change, but the two values have the same sign...
066 if ((val1 ^ sum) < 0 && (val1 ^ val2) >= 0) {
067 throw new ArithmeticException
068 ("The calculation caused an overflow: " + val1 + " + " + val2);
069 }
070 return sum;
071 }
072
073 /**
074 * Add two values throwing an exception if overflow occurs.
075 *
076 * @param val1 the first value
077 * @param val2 the second value
078 * @return the new total
079 * @throws ArithmeticException if the value is too big or too small
080 */
081 public static long safeAdd(long val1, long val2) {
082 long sum = val1 + val2;
083 // If there is a sign change, but the two values have the same sign...
084 if ((val1 ^ sum) < 0 && (val1 ^ val2) >= 0) {
085 throw new ArithmeticException
086 ("The calculation caused an overflow: " + val1 + " + " + val2);
087 }
088 return sum;
089 }
090
091 /**
092 * Subtracts two values throwing an exception if overflow occurs.
093 *
094 * @param val1 the first value, to be taken away from
095 * @param val2 the second value, the amount to take away
096 * @return the new total
097 * @throws ArithmeticException if the value is too big or too small
098 */
099 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 (val1 == 1) {
166 return val2;
167 }
168 if (val1 == 0 || val2 == 0) {
169 return 0;
170 }
171 long total = val1 * val2;
172 if (total / val2 != val1 || val1 == Long.MIN_VALUE && val2 == -1 || val2 == Long.MIN_VALUE && val1 == -1) {
173 throw new ArithmeticException("Multiplication overflows a long: " + val1 + " * " + val2);
174 }
175 return total;
176 }
177
178 /**
179 * Casts to an int throwing an exception if overflow occurs.
180 *
181 * @param value the value
182 * @return the value as an int
183 * @throws ArithmeticException if the value is too big or too small
184 */
185 public static int safeToInt(long value) {
186 if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) {
187 return (int) value;
188 }
189 throw new ArithmeticException("Value cannot fit in an int: " + value);
190 }
191
192 /**
193 * Multiply two values to return an int throwing an exception if overflow occurs.
194 *
195 * @param val1 the first value
196 * @param val2 the second value
197 * @return the new total
198 * @throws ArithmeticException if the value is too big or too small
199 */
200 public static int safeMultiplyToInt(long val1, long val2) {
201 long val = FieldUtils.safeMultiply(val1, val2);
202 return FieldUtils.safeToInt(val);
203 }
204
205 //-----------------------------------------------------------------------
206 /**
207 * Verify that input values are within specified bounds.
208 *
209 * @param value the value to check
210 * @param lowerBound the lower bound allowed for value
211 * @param upperBound the upper bound allowed for value
212 * @throws IllegalFieldValueException if value is not in the specified bounds
213 */
214 public static void verifyValueBounds(DateTimeField field,
215 int value, int lowerBound, int upperBound) {
216 if ((value < lowerBound) || (value > upperBound)) {
217 throw new IllegalFieldValueException
218 (field.getType(), Integer.valueOf(value),
219 Integer.valueOf(lowerBound), Integer.valueOf(upperBound));
220 }
221 }
222
223 /**
224 * Verify that input values are within specified bounds.
225 *
226 * @param value the value to check
227 * @param lowerBound the lower bound allowed for value
228 * @param upperBound the upper bound allowed for value
229 * @throws IllegalFieldValueException if value is not in the specified bounds
230 * @since 1.1
231 */
232 public static void verifyValueBounds(DateTimeFieldType fieldType,
233 int value, int lowerBound, int upperBound) {
234 if ((value < lowerBound) || (value > upperBound)) {
235 throw new IllegalFieldValueException
236 (fieldType, Integer.valueOf(value),
237 Integer.valueOf(lowerBound), Integer.valueOf(upperBound));
238 }
239 }
240
241 /**
242 * Verify that input values are within specified bounds.
243 *
244 * @param value the value to check
245 * @param lowerBound the lower bound allowed for value
246 * @param upperBound the upper bound allowed for value
247 * @throws IllegalFieldValueException if value is not in the specified bounds
248 */
249 public static void verifyValueBounds(String fieldName,
250 int value, int lowerBound, int upperBound) {
251 if ((value < lowerBound) || (value > upperBound)) {
252 throw new IllegalFieldValueException
253 (fieldName, Integer.valueOf(value),
254 Integer.valueOf(lowerBound), Integer.valueOf(upperBound));
255 }
256 }
257
258 /**
259 * Utility method used by addWrapField implementations to ensure the new
260 * value lies within the field's legal value range.
261 *
262 * @param currentValue the current value of the data, which may lie outside
263 * the wrapped value range
264 * @param wrapValue the value to add to current value before
265 * wrapping. This may be negative.
266 * @param minValue the wrap range minimum value.
267 * @param maxValue the wrap range maximum value. This must be
268 * greater than minValue (checked by the method).
269 * @return the wrapped value
270 * @throws IllegalArgumentException if minValue is greater
271 * than or equal to maxValue
272 */
273 public static int getWrappedValue(int currentValue, int wrapValue,
274 int minValue, int maxValue) {
275 return getWrappedValue(currentValue + wrapValue, minValue, maxValue);
276 }
277
278 /**
279 * Utility method that ensures the given value lies within the field's
280 * legal value range.
281 *
282 * @param value the value to fit into the wrapped value range
283 * @param minValue the wrap range minimum value.
284 * @param maxValue the wrap range maximum value. This must be
285 * greater than minValue (checked by the method).
286 * @return the wrapped value
287 * @throws IllegalArgumentException if minValue is greater
288 * than or equal to maxValue
289 */
290 public static int getWrappedValue(int value, int minValue, int maxValue) {
291 if (minValue >= maxValue) {
292 throw new IllegalArgumentException("MIN > MAX");
293 }
294
295 int wrapRange = maxValue - minValue + 1;
296 value -= minValue;
297
298 if (value >= 0) {
299 return (value % wrapRange) + minValue;
300 }
301
302 int remByRange = (-value) % wrapRange;
303
304 if (remByRange == 0) {
305 return 0 + minValue;
306 }
307 return (wrapRange - remByRange) + minValue;
308 }
309
310 //-----------------------------------------------------------------------
311 /**
312 * Compares two objects as equals handling null.
313 *
314 * @param object1 the first object
315 * @param object2 the second object
316 * @return true if equal
317 * @since 1.4
318 */
319 public static boolean equals(Object object1, Object object2) {
320 if (object1 == object2) {
321 return true;
322 }
323 if (object1 == null || object2 == null) {
324 return false;
325 }
326 return object1.equals(object2);
327 }
328
329 }