1. /* ====================================================================
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowledgement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowledgement may appear in the software itself,
  24. * if and wherever such third-party acknowledgements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Commons", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Software Foundation.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.commons.lang.math;
  55. /**
  56. * <p><code>Range</code> represents a range of numbers of the same type.</p>
  57. *
  58. * <p>Specific subclasses hold the range values as different types. Each
  59. * subclass should be immutable and {@link java.io.Serializable Serializable}
  60. * if possible.</p>
  61. *
  62. * @author Stephen Colebourne
  63. * @since 2.0
  64. * @version $Id: Range.java,v 1.5 2003/08/18 02:22:24 bayard Exp $
  65. */
  66. public abstract class Range {
  67. /**
  68. * <p>Constructs a new range.</p>
  69. */
  70. public Range() {
  71. super();
  72. }
  73. // Accessors
  74. //--------------------------------------------------------------------
  75. /**
  76. * <p>Gets the minimum number in this range.</p>
  77. *
  78. * @return the minimum number in this range
  79. */
  80. public abstract Number getMinimumNumber();
  81. /**
  82. * <p>Gets the minimum number in this range as a <code>long</code>.</p>
  83. *
  84. * <p>This implementation uses the {@link #getMinimumNumber()} method.
  85. * Subclasses may be able to optimise this.</p>
  86. *
  87. * @return the minimum number in this range
  88. */
  89. public long getMinimumLong() {
  90. return getMinimumNumber().longValue();
  91. }
  92. /**
  93. * <p>Gets the minimum number in this range as a <code>int</code>.</p>
  94. *
  95. * <p>This implementation uses the {@link #getMinimumNumber()} method.
  96. * Subclasses may be able to optimise this.</p>
  97. *
  98. * @return the minimum number in this range
  99. */
  100. public int getMinimumInteger() {
  101. return getMinimumNumber().intValue();
  102. }
  103. /**
  104. * <p>Gets the minimum number in this range as a <code>double</code>.</p>
  105. *
  106. * <p>This implementation uses the {@link #getMinimumNumber()} method.
  107. * Subclasses may be able to optimise this.</p>
  108. *
  109. * @return the minimum number in this range
  110. */
  111. public double getMinimumDouble() {
  112. return getMinimumNumber().doubleValue();
  113. }
  114. /**
  115. * <p>Gets the minimum number in this range as a <code>float</code>.</p>
  116. *
  117. * <p>This implementation uses the {@link #getMinimumNumber()} method.
  118. * Subclasses may be able to optimise this.</p>
  119. *
  120. * @return the minimum number in this range
  121. */
  122. public float getMinimumFloat() {
  123. return getMinimumNumber().floatValue();
  124. }
  125. /**
  126. * <p>Gets the maximum number in this range.</p>
  127. *
  128. * @return the maximum number in this range
  129. */
  130. public abstract Number getMaximumNumber();
  131. /**
  132. * <p>Gets the maximum number in this range as a <code>long</code>.</p>
  133. *
  134. * <p>This implementation uses the {@link #getMaximumNumber()} method.
  135. * Subclasses may be able to optimise this.</p>
  136. *
  137. * @return the maximum number in this range
  138. */
  139. public long getMaximumLong() {
  140. return getMaximumNumber().longValue();
  141. }
  142. /**
  143. * <p>Gets the maximum number in this range as a <code>int</code>.</p>
  144. *
  145. * <p>This implementation uses the {@link #getMaximumNumber()} method.
  146. * Subclasses may be able to optimise this.</p>
  147. *
  148. * @return the maximum number in this range
  149. */
  150. public int getMaximumInteger() {
  151. return getMaximumNumber().intValue();
  152. }
  153. /**
  154. * <p>Gets the maximum number in this range as a <code>double</code>.</p>
  155. *
  156. * <p>This implementation uses the {@link #getMaximumNumber()} method.
  157. * Subclasses may be able to optimise this.</p>
  158. *
  159. * @return the maximum number in this range
  160. */
  161. public double getMaximumDouble() {
  162. return getMaximumNumber().doubleValue();
  163. }
  164. /**
  165. * <p>Gets the maximum number in this range as a <code>float</code>.</p>
  166. *
  167. * <p>This implementation uses the {@link #getMaximumNumber()} method.
  168. * Subclasses may be able to optimise this.</p>
  169. *
  170. * @return the maximum number in this range
  171. */
  172. public float getMaximumFloat() {
  173. return getMaximumNumber().floatValue();
  174. }
  175. // Include tests
  176. //--------------------------------------------------------------------
  177. /**
  178. * <p>Tests whether the specified <code>Number</code> occurs within
  179. * this range.</p>
  180. *
  181. * <p>The exact comparison implementation varies by subclass. It is
  182. * intended that an <code>int</code> specific subclass will compare using
  183. * <code>int</code> comparison.</p>
  184. *
  185. * <p><code>null</code> is handled and returns <code>false</code>.</p>
  186. *
  187. * @param number the number to test, may be <code>null</code>
  188. * @return <code>true</code> if the specified number occurs within this range
  189. * @throws IllegalArgumentException if the <code>Number</code> cannot be compared
  190. */
  191. public abstract boolean containsNumber(Number number);
  192. /**
  193. * <p>Tests whether the specified <code>Number</code> occurs within
  194. * this range using <code>long</code> comparison..</p>
  195. *
  196. * <p><code>null</code> is handled and returns <code>false</code>.</p>
  197. *
  198. * <p>This implementation forwards to the {@link #containsLong(long)} method.</p>
  199. *
  200. * @param value the long to test, may be <code>null</code>
  201. * @return <code>true</code> if the specified number occurs within this
  202. * range by <code>long</code> comparison
  203. */
  204. public boolean containsLong(Number value) {
  205. if (value == null) {
  206. return false;
  207. }
  208. return containsLong(value.longValue());
  209. }
  210. /**
  211. * <p>Tests whether the specified <code>long</code> occurs within
  212. * this range using <code>long</code> comparison.</p>
  213. *
  214. * <p>This implementation uses the {@link #getMinimumLong()} and
  215. * {@link #getMaximumLong()} methods and should be good for most uses.</p>
  216. *
  217. * @param value the long to test
  218. * @return <code>true</code> if the specified number occurs within this
  219. * range by <code>long</code> comparison
  220. */
  221. public boolean containsLong(long value) {
  222. return (value >= getMinimumLong() && value <= getMaximumLong());
  223. }
  224. /**
  225. * <p>Tests whether the specified <code>Number</code> occurs within
  226. * this range using <code>int</code> comparison..</p>
  227. *
  228. * <p><code>null</code> is handled and returns <code>false</code>.</p>
  229. *
  230. * <p>This implementation forwards to the {@link #containsInteger(int)} method.</p>
  231. *
  232. * @param value the integer to test, may be <code>null</code>
  233. * @return <code>true</code> if the specified number occurs within this
  234. * range by <code>int</code> comparison
  235. */
  236. public boolean containsInteger(Number value) {
  237. if (value == null) {
  238. return false;
  239. }
  240. return containsInteger(value.intValue());
  241. }
  242. /**
  243. * <p>Tests whether the specified <code>int</code> occurs within
  244. * this range using <code>int</code> comparison.</p>
  245. *
  246. * <p>This implementation uses the {@link #getMinimumInteger()} and
  247. * {@link #getMaximumInteger()} methods and should be good for most uses.</p>
  248. *
  249. * @param value the int to test
  250. * @return <code>true</code> if the specified number occurs within this
  251. * range by <code>int</code> comparison
  252. */
  253. public boolean containsInteger(int value) {
  254. return (value >= getMinimumInteger() && value <= getMaximumInteger());
  255. }
  256. /**
  257. * <p>Tests whether the specified <code>Number</code> occurs within
  258. * this range using <code>double</code> comparison..</p>
  259. *
  260. * <p><code>null</code> is handled and returns <code>false</code>.</p>
  261. *
  262. * <p>This implementation forwards to the {@link #containsDouble(double)} method.</p>
  263. *
  264. * @param value the double to test, may be <code>null</code>
  265. * @return <code>true</code> if the specified number occurs within this
  266. * range by <code>double</code> comparison
  267. */
  268. public boolean containsDouble(Number value) {
  269. if (value == null) {
  270. return false;
  271. }
  272. return containsDouble(value.doubleValue());
  273. }
  274. /**
  275. * <p>Tests whether the specified <code>double</code> occurs within
  276. * this range using <code>double</code> comparison.</p>
  277. *
  278. * <p>This implementation uses the {@link #getMinimumDouble()} and
  279. * {@link #getMaximumDouble()} methods and should be good for most uses.</p>
  280. *
  281. * @param value the double to test
  282. * @return <code>true</code> if the specified number occurs within this
  283. * range by <code>double</code> comparison
  284. */
  285. public boolean containsDouble(double value) {
  286. int compareMin = NumberUtils.compare(getMinimumDouble(), value);
  287. int compareMax = NumberUtils.compare(getMaximumDouble(), value);
  288. return (compareMin <= 0 && compareMax >= 0);
  289. }
  290. /**
  291. * <p>Tests whether the specified <code>Number</code> occurs within
  292. * this range using <code>float</code> comparison.</p>
  293. *
  294. * <p><code>null</code> is handled and returns <code>false</code>.</p>
  295. *
  296. * <p>This implementation forwards to the {@link #containsFloat(float)} method.</p>
  297. *
  298. * @param value the float to test, may be <code>null</code>
  299. * @return <code>true</code> if the specified number occurs within this
  300. * range by <code>float</code> comparison
  301. */
  302. public boolean containsFloat(Number value) {
  303. if (value == null) {
  304. return false;
  305. }
  306. return containsFloat(value.floatValue());
  307. }
  308. /**
  309. * <p>Tests whether the specified <code>float</code> occurs within
  310. * this range using <code>float</code> comparison.</p>
  311. *
  312. * <p>This implementation uses the {@link #getMinimumFloat()} and
  313. * {@link #getMaximumFloat()} methods and should be good for most uses.</p>
  314. *
  315. * @param value the float to test
  316. * @return <code>true</code> if the specified number occurs within this
  317. * range by <code>float</code> comparison
  318. */
  319. public boolean containsFloat(float value) {
  320. int compareMin = NumberUtils.compare(getMinimumFloat(), value);
  321. int compareMax = NumberUtils.compare(getMaximumFloat(), value);
  322. return (compareMin <= 0 && compareMax >= 0);
  323. }
  324. // Range tests
  325. //--------------------------------------------------------------------
  326. /**
  327. * <p>Tests whether the specified range occurs entirely within this range.</p>
  328. *
  329. * <p>The exact comparison implementation varies by subclass. It is
  330. * intended that an <code>int</code> specific subclass will compare using
  331. * <code>int</code> comparison.</p>
  332. *
  333. * <p><code>null</code> is handled and returns <code>false</code>.</p>
  334. *
  335. * <p>This implementation uses the {@link #containsNumber(Number)} method.
  336. * Subclasses may be able to optimise this.</p>
  337. *
  338. * @param range the range to test, may be <code>null</code>
  339. * @return <code>true</code> if the specified range occurs entirely within
  340. * this range; otherwise, <code>false</code>
  341. * @throws IllegalArgumentException if the <code>Range</code> cannot be compared
  342. */
  343. public boolean containsRange(Range range) {
  344. if (range == null) {
  345. return false;
  346. }
  347. return containsNumber(range.getMinimumNumber())
  348. && containsNumber(range.getMaximumNumber());
  349. }
  350. /**
  351. * <p>Tests whether the specified range overlaps with this range.</p>
  352. *
  353. * <p>The exact comparison implementation varies by subclass. It is
  354. * intended that an <code>int</code> specific subclass will compare using
  355. * <code>int</code> comparison.</p>
  356. *
  357. * <p><code>null</code> is handled and returns <code>false</code>.</p>
  358. *
  359. * <p>This implementation uses the {@link #containsNumber(Number)} and
  360. * {@link #containsRange(Range)} methods.
  361. * Subclasses may be able to optimise this.</p>
  362. *
  363. * @param range the range to test, may be <code>null</code>
  364. * @return <code>true</code> if the specified range overlaps with this
  365. * range; otherwise, <code>false</code>
  366. * @throws IllegalArgumentException if the <code>Range</code> cannot be compared
  367. */
  368. public boolean overlapsRange(Range range) {
  369. if (range == null) {
  370. return false;
  371. }
  372. return range.containsNumber(getMinimumNumber())
  373. || range.containsNumber(getMaximumNumber())
  374. || containsNumber(range.getMinimumNumber());
  375. }
  376. // Basics
  377. //--------------------------------------------------------------------
  378. /**
  379. * <p>Compares this range to another object to test if they are equal.</p>.
  380. *
  381. * <p>To be equal, the class, minimum and maximum must be equal.</p>
  382. *
  383. * <p>This implementation uses the {@link #getMinimumNumber()} and
  384. * {@link #getMaximumNumber()} methods.
  385. * Subclasses may be able to optimise this.</p>
  386. *
  387. * @param obj the reference object with which to compare
  388. * @return <code>true</code> if this object is equal
  389. */
  390. public boolean equals(Object obj) {
  391. if (obj == this) {
  392. return true;
  393. } else if (obj == null || obj.getClass() != getClass()) {
  394. return false;
  395. } else {
  396. Range range = (Range) obj;
  397. return getMinimumNumber().equals(range.getMinimumNumber()) &&
  398. getMaximumNumber().equals(range.getMaximumNumber());
  399. }
  400. }
  401. /**
  402. * <p>Gets a hashCode for the range.</p>
  403. *
  404. * <p>This implementation uses the {@link #getMinimumNumber()} and
  405. * {@link #getMaximumNumber()} methods.
  406. * Subclasses may be able to optimise this.</p>
  407. *
  408. * @return a hash code value for this object
  409. */
  410. public int hashCode() {
  411. int result = 17;
  412. result = 37 * result + getClass().hashCode();
  413. result = 37 * result + getMinimumNumber().hashCode();
  414. result = 37 * result + getMaximumNumber().hashCode();
  415. return result;
  416. }
  417. /**
  418. * <p>Gets the range as a <code>String</code>.</p>
  419. *
  420. * <p>The format of the String is 'Range[<i>min</i>,<i>max</i>]'.</p>
  421. *
  422. * <p>This implementation uses the {@link #getMinimumNumber()} and
  423. * {@link #getMaximumNumber()} methods.
  424. * Subclasses may be able to optimise this.</p>
  425. *
  426. * @return the <code>String</code> representation of this range
  427. */
  428. public String toString() {
  429. StringBuffer buf = new StringBuffer(32);
  430. buf.append("Range[");
  431. buf.append(getMinimumNumber());
  432. buf.append(',');
  433. buf.append(getMaximumNumber());
  434. buf.append(']');
  435. return buf.toString();
  436. }
  437. }