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 */
016package org.joda.time.field;
017
018import org.joda.time.DateTimeField;
019import org.joda.time.DateTimeFieldType;
020import 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 */
030public 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("Multiplication overflows an int: " + val1 + " * " + val2);
122        }
123        return (int) total;
124    }
125
126    /**
127     * Multiply two values throwing an exception if overflow occurs.
128     * 
129     * @param val1  the first value
130     * @param val2  the second value
131     * @return the new total
132     * @throws ArithmeticException if the value is too big or too small
133     * @since 1.2
134     */
135    public static long safeMultiply(long val1, int val2) {
136        switch (val2) {
137            case -1:
138                if (val1 == Long.MIN_VALUE) {
139                    throw new ArithmeticException("Multiplication overflows a long: " + val1 + " * " + val2);
140                }
141                return -val1;
142            case 0:
143                return 0L;
144            case 1:
145                return val1;
146        }
147        long total = val1 * val2;
148        if (total / val2 != val1) {
149          throw new ArithmeticException("Multiplication overflows a long: " + val1 + " * " + val2);
150        }
151        return total;
152    }
153
154    /**
155     * Multiply two values throwing an exception if overflow occurs.
156     * 
157     * @param val1  the first value
158     * @param val2  the second value
159     * @return the new total
160     * @throws ArithmeticException if the value is too big or too small
161     */
162    public static long safeMultiply(long val1, long val2) {
163        if (val2 == 1) {
164            return val1;
165        }
166        if (val1 == 1) {
167            return val2;
168        }
169        if (val1 == 0 || val2 == 0) {
170            return 0;
171        }
172        long total = val1 * val2;
173        if (total / val2 != val1 || val1 == Long.MIN_VALUE && val2 == -1 || val2 == Long.MIN_VALUE && val1 == -1) {
174            throw new ArithmeticException("Multiplication overflows a long: " + val1 + " * " + val2);
175        }
176        return total;
177    }
178    
179    /**
180     * Casts to an int throwing an exception if overflow occurs.
181     * 
182     * @param value  the value
183     * @return the value as an int
184     * @throws ArithmeticException if the value is too big or too small
185     */
186    public static int safeToInt(long value) {
187        if (Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE) {
188            return (int) value;
189        }
190        throw new ArithmeticException("Value cannot fit in an int: " + value);
191    }
192    
193    /**
194     * Multiply two values to return an int throwing an exception if overflow occurs.
195     * 
196     * @param val1  the first value
197     * @param val2  the second value
198     * @return the new total
199     * @throws ArithmeticException if the value is too big or too small
200     */
201    public static int safeMultiplyToInt(long val1, long val2) {
202        long val = FieldUtils.safeMultiply(val1, val2);
203        return FieldUtils.safeToInt(val);
204    }
205
206    //-----------------------------------------------------------------------
207    /**
208     * Verify that input values are within specified bounds.
209     * 
210     * @param value  the value to check
211     * @param lowerBound  the lower bound allowed for value
212     * @param upperBound  the upper bound allowed for value
213     * @throws IllegalFieldValueException if value is not in the specified bounds
214     */
215    public static void verifyValueBounds(DateTimeField field, 
216                                         int value, int lowerBound, int upperBound) {
217        if ((value < lowerBound) || (value > upperBound)) {
218            throw new IllegalFieldValueException
219                (field.getType(), Integer.valueOf(value),
220                 Integer.valueOf(lowerBound), Integer.valueOf(upperBound));
221        }
222    }
223
224    /**
225     * Verify that input values are within specified bounds.
226     * 
227     * @param value  the value to check
228     * @param lowerBound  the lower bound allowed for value
229     * @param upperBound  the upper bound allowed for value
230     * @throws IllegalFieldValueException if value is not in the specified bounds
231     * @since 1.1
232     */
233    public static void verifyValueBounds(DateTimeFieldType fieldType, 
234                                         int value, int lowerBound, int upperBound) {
235        if ((value < lowerBound) || (value > upperBound)) {
236            throw new IllegalFieldValueException
237                (fieldType, Integer.valueOf(value),
238                 Integer.valueOf(lowerBound), Integer.valueOf(upperBound));
239        }
240    }
241
242    /**
243     * Verify that input values are within specified bounds.
244     * 
245     * @param value  the value to check
246     * @param lowerBound  the lower bound allowed for value
247     * @param upperBound  the upper bound allowed for value
248     * @throws IllegalFieldValueException if value is not in the specified bounds
249     */
250    public static void verifyValueBounds(String fieldName,
251                                         int value, int lowerBound, int upperBound) {
252        if ((value < lowerBound) || (value > upperBound)) {
253            throw new IllegalFieldValueException
254                (fieldName, Integer.valueOf(value),
255                 Integer.valueOf(lowerBound), Integer.valueOf(upperBound));
256        }
257    }
258
259    /**
260     * Utility method used by addWrapField implementations to ensure the new
261     * value lies within the field's legal value range.
262     *
263     * @param currentValue the current value of the data, which may lie outside
264     * the wrapped value range
265     * @param wrapValue  the value to add to current value before
266     *  wrapping.  This may be negative.
267     * @param minValue the wrap range minimum value.
268     * @param maxValue the wrap range maximum value.  This must be
269     *  greater than minValue (checked by the method).
270     * @return the wrapped value
271     * @throws IllegalArgumentException if minValue is greater
272     *  than or equal to maxValue
273     */
274    public static int getWrappedValue(int currentValue, int wrapValue,
275                                      int minValue, int maxValue) {
276        return getWrappedValue(currentValue + wrapValue, minValue, maxValue);
277    }
278
279    /**
280     * Utility method that ensures the given value lies within the field's
281     * legal value range.
282     * 
283     * @param value  the value to fit into the wrapped value range
284     * @param minValue the wrap range minimum value.
285     * @param maxValue the wrap range maximum value.  This must be
286     *  greater than minValue (checked by the method).
287     * @return the wrapped value
288     * @throws IllegalArgumentException if minValue is greater
289     *  than or equal to maxValue
290     */
291    public static int getWrappedValue(int value, int minValue, int maxValue) {
292        if (minValue >= maxValue) {
293            throw new IllegalArgumentException("MIN > MAX");
294        }
295
296        int wrapRange = maxValue - minValue + 1;
297        value -= minValue;
298
299        if (value >= 0) {
300            return (value % wrapRange) + minValue;
301        }
302
303        int remByRange = (-value) % wrapRange;
304
305        if (remByRange == 0) {
306            return 0 + minValue;
307        }
308        return (wrapRange - remByRange) + minValue;
309    }
310
311    //-----------------------------------------------------------------------
312    /**
313     * Compares two objects as equals handling null.
314     * 
315     * @param object1  the first object
316     * @param object2  the second object
317     * @return true if equal
318     * @since 1.4
319     */
320    public static boolean equals(Object object1, Object object2) {
321        if (object1 == object2) {
322            return true;
323        }
324        if (object1 == null || object2 == null) {
325            return false;
326        }
327        return object1.equals(object2);
328    }
329
330}