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(
051: "Integer.MIN_VALUE cannot be negated");
052: }
053: return -value;
054: }
055:
056: /**
057: * Add two values throwing an exception if overflow occurs.
058: *
059: * @param val1 the first value
060: * @param val2 the second value
061: * @return the new total
062: * @throws ArithmeticException if the value is too big or too small
063: */
064: public static int safeAdd(int val1, int val2) {
065: int sum = val1 + val2;
066: // If there is a sign change, but the two values have the same sign...
067: if ((val1 ^ sum) < 0 && (val1 ^ val2) >= 0) {
068: throw new ArithmeticException(
069: "The calculation caused an overflow: " + val1
070: + " + " + val2);
071: }
072: return sum;
073: }
074:
075: /**
076: * Add two values throwing an exception if overflow occurs.
077: *
078: * @param val1 the first value
079: * @param val2 the second value
080: * @return the new total
081: * @throws ArithmeticException if the value is too big or too small
082: */
083: public static long safeAdd(long val1, long val2) {
084: long sum = val1 + val2;
085: // If there is a sign change, but the two values have the same sign...
086: if ((val1 ^ sum) < 0 && (val1 ^ val2) >= 0) {
087: throw new ArithmeticException(
088: "The calculation caused an overflow: " + val1
089: + " + " + val2);
090: }
091: return sum;
092: }
093:
094: /**
095: * Subtracts two values throwing an exception if overflow occurs.
096: *
097: * @param val1 the first value, to be taken away from
098: * @param val2 the second value, the amount to take away
099: * @return the new total
100: * @throws ArithmeticException if the value is too big or too small
101: */
102: public static long safeSubtract(long val1, long val2) {
103: long diff = val1 - val2;
104: // If there is a sign change, but the two values have different signs...
105: if ((val1 ^ diff) < 0 && (val1 ^ val2) < 0) {
106: throw new ArithmeticException(
107: "The calculation caused an overflow: " + val1
108: + " - " + val2);
109: }
110: return diff;
111: }
112:
113: /**
114: * Multiply two values throwing an exception if overflow occurs.
115: *
116: * @param val1 the first value
117: * @param val2 the second value
118: * @return the new total
119: * @throws ArithmeticException if the value is too big or too small
120: * @since 1.2
121: */
122: public static int safeMultiply(int val1, int val2) {
123: long total = (long) val1 * (long) val2;
124: if (total < Integer.MIN_VALUE || total > Integer.MAX_VALUE) {
125: throw new ArithmeticException(
126: "The calculation caused an overflow: " + val1
127: + " * " + val2);
128: }
129: return (int) total;
130: }
131:
132: /**
133: * Multiply two values throwing an exception if overflow occurs.
134: *
135: * @param val1 the first value
136: * @param scalar the second value
137: * @return the new total
138: * @throws ArithmeticException if the value is too big or too small
139: * @since 1.2
140: */
141: public static long safeMultiply(long val1, int scalar) {
142: switch (scalar) {
143: case -1:
144: return -val1;
145: case 0:
146: return 0L;
147: case 1:
148: return val1;
149: }
150: long total = val1 * scalar;
151: if (total / scalar != val1) {
152: throw new ArithmeticException(
153: "The calculation caused an overflow: " + val1
154: + " * " + scalar);
155: }
156: return total;
157: }
158:
159: /**
160: * Multiply two values throwing an exception if overflow occurs.
161: *
162: * @param val1 the first value
163: * @param val2 the second value
164: * @return the new total
165: * @throws ArithmeticException if the value is too big or too small
166: */
167: public static long safeMultiply(long val1, long val2) {
168: if (val2 == 1) {
169: return val1;
170: }
171: if (val2 == 0) {
172: return 0;
173: }
174: long total = val1 * val2;
175: if (total / val2 != val1) {
176: throw new ArithmeticException(
177: "The calculation caused an overflow: " + val1
178: + " * " + val2);
179: }
180: return total;
181: }
182:
183: /**
184: * Casts to an int throwing an exception if overflow occurs.
185: *
186: * @param value the value
187: * @return the value as an int
188: * @throws ArithmeticException if the value is too big or too small
189: */
190: public static int safeToInt(long value) {
191: if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) {
192: return (int) value;
193: }
194: throw new ArithmeticException("Value cannot fit in an int: "
195: + value);
196: }
197:
198: /**
199: * Multiply two values to return an int throwing an exception if overflow occurs.
200: *
201: * @param val1 the first value
202: * @param val2 the second value
203: * @return the new total
204: * @throws ArithmeticException if the value is too big or too small
205: */
206: public static int safeMultiplyToInt(long val1, long val2) {
207: long val = FieldUtils.safeMultiply(val1, val2);
208: return FieldUtils.safeToInt(val);
209: }
210:
211: //-----------------------------------------------------------------------
212: /**
213: * Verify that input values are within specified bounds.
214: *
215: * @param value the value to check
216: * @param lowerBound the lower bound allowed for value
217: * @param upperBound the upper bound allowed for value
218: * @throws IllegalFieldValueException if value is not in the specified bounds
219: */
220: public static void verifyValueBounds(DateTimeField field,
221: int value, int lowerBound, int upperBound) {
222: if ((value < lowerBound) || (value > upperBound)) {
223: throw new IllegalFieldValueException(field.getType(),
224: new Integer(value), new Integer(lowerBound),
225: new Integer(upperBound));
226: }
227: }
228:
229: /**
230: * Verify that input values are within specified bounds.
231: *
232: * @param value the value to check
233: * @param lowerBound the lower bound allowed for value
234: * @param upperBound the upper bound allowed for value
235: * @throws IllegalFieldValueException if value is not in the specified bounds
236: * @since 1.1
237: */
238: public static void verifyValueBounds(DateTimeFieldType fieldType,
239: int value, int lowerBound, int upperBound) {
240: if ((value < lowerBound) || (value > upperBound)) {
241: throw new IllegalFieldValueException(fieldType,
242: new Integer(value), new Integer(lowerBound),
243: new Integer(upperBound));
244: }
245: }
246:
247: /**
248: * Verify that input values are within specified bounds.
249: *
250: * @param value the value to check
251: * @param lowerBound the lower bound allowed for value
252: * @param upperBound the upper bound allowed for value
253: * @throws IllegalFieldValueException if value is not in the specified bounds
254: */
255: public static void verifyValueBounds(String fieldName, int value,
256: int lowerBound, int upperBound) {
257: if ((value < lowerBound) || (value > upperBound)) {
258: throw new IllegalFieldValueException(fieldName,
259: new Integer(value), new Integer(lowerBound),
260: new Integer(upperBound));
261: }
262: }
263:
264: /**
265: * Utility method used by addWrapField implementations to ensure the new
266: * value lies within the field's legal value range.
267: *
268: * @param currentValue the current value of the data, which may lie outside
269: * the wrapped value range
270: * @param wrapValue the value to add to current value before
271: * wrapping. This may be negative.
272: * @param minValue the wrap range minimum value.
273: * @param maxValue the wrap range maximum value. This must be
274: * greater than minValue (checked by the method).
275: * @return the wrapped value
276: * @throws IllegalArgumentException if minValue is greater
277: * than or equal to maxValue
278: */
279: public static int getWrappedValue(int currentValue, int wrapValue,
280: int minValue, int maxValue) {
281: return getWrappedValue(currentValue + wrapValue, minValue,
282: maxValue);
283: }
284:
285: /**
286: * Utility method that ensures the given value lies within the field's
287: * legal value range.
288: *
289: * @param value the value to fit into the wrapped value range
290: * @param minValue the wrap range minimum value.
291: * @param maxValue the wrap range maximum value. This must be
292: * greater than minValue (checked by the method).
293: * @return the wrapped value
294: * @throws IllegalArgumentException if minValue is greater
295: * than or equal to maxValue
296: */
297: public static int getWrappedValue(int value, int minValue,
298: int maxValue) {
299: if (minValue >= maxValue) {
300: throw new IllegalArgumentException("MIN > MAX");
301: }
302:
303: int wrapRange = maxValue - minValue + 1;
304: value -= minValue;
305:
306: if (value >= 0) {
307: return (value % wrapRange) + minValue;
308: }
309:
310: int remByRange = (-value) % wrapRange;
311:
312: if (remByRange == 0) {
313: return 0 + minValue;
314: }
315: return (wrapRange - remByRange) + minValue;
316: }
317:
318: //-----------------------------------------------------------------------
319: /**
320: * Compares two objects as equals handling null.
321: *
322: * @param object1 the first object
323: * @param object2 the second object
324: * @return true if equal
325: * @since 1.4
326: */
327: public static boolean equals(Object object1, Object object2) {
328: if (object1 == object2) {
329: return true;
330: }
331: if (object1 == null || object2 == null) {
332: return false;
333: }
334: return object1.equals(object2);
335: }
336:
337: }
|