View Javadoc

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("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 }