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 (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(), Integer.valueOf(value), 217 Integer.valueOf(lowerBound), Integer.valueOf(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, Integer.valueOf(value), 235 Integer.valueOf(lowerBound), Integer.valueOf(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, Integer.valueOf(value), 252 Integer.valueOf(lowerBound), Integer.valueOf(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 }