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 }