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