/** * This Source Code Form is subject to the terms of the Mozilla Public License, * v. 2.0. If a copy of the MPL was not distributed with this file, You can * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. * * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS * graphic logo is a trademark of OpenMRS Inc. */ package org.openmrs.util; import org.apache.commons.lang3.builder.HashCodeBuilder; /** * Represents a bounded or unbounded numeric range. By default the range is closed (ake inclusive) * on the low end and open (aka exclusive) on the high end: mathematically "[low, high)". (I'm not * using the similarly-named class from Apache commons because it doesn't implement comparable, and * because it only allows inclusive bounds.) */ public class DoubleRange implements Comparable<DoubleRange> { private Double low; private Double high; private boolean closedLow = true; //TODO: add setters and getters for these private boolean closedHigh = false; /** * @should return null low and high if accessors are not called */ public DoubleRange() { } /** * @should return infinite low and high if called with null parameters */ public DoubleRange(Double low, Double high) { this.low = low == null ? new Double(Double.NEGATIVE_INFINITY) : low; this.high = high == null ? new Double(Double.POSITIVE_INFINITY) : high; } /** * @return Returns the high. * @should return correct value of high if it high was set previously * @should return positive infinity if high was not set previously */ public Double getHigh() { return high; } /** * @param high The high to set. * @should set high to positive infinity on null parameter * @should cause low to have the set value */ public void setHigh(Double high) { this.high = high == null ? new Double(Double.POSITIVE_INFINITY) : high; } /** * @return Returns the low. * @should return correct value of low if low was set previously * @should return negative infinity if low was not set previously */ public Double getLow() { return low; } /** * @param low The low to set. * @should set low to negative infinity on null parameter * @should cause low to have the set value */ public void setLow(Double low) { this.low = low == null ? new Double(Double.NEGATIVE_INFINITY) : low; } /** * first sorts according to low-bound (ascending) then according to high-bound (descending) * @should return plus 1 if this low is greater than other low * @should return minus one if this low is lower than other low * @should return plus one if both lows are equal but other high is greater than this high * @should return minus one if both lows are equal but other high is less than this high * @should return zero if both lows and both highs are equal * @should return 1 if this range is wider than other range */ @Override public int compareTo(DoubleRange other) { int temp = low.compareTo(other.low); if (temp == 0) { temp = other.high.compareTo(high); } return temp; } /** * BUG: this method should return false if both ends of the range are null. * It currently returns true in this case. * * checks whether a double is in this range * @param d the Double to check for in this range * @return true if d is in this range, false otherwise * @should return true if parameter is in range * @should return false if parameter is not in range * @should return false if parameter is equal to high * @should return true if parameter is equal to low * @should return false if parameter is lower than low * @should return false if both low and high are null */ public boolean contains(double d) { if (low != null) { if (closedLow) { if (d < low) { return false; } } else { //unreachable code as closedLow is never set to false anywhere if (d <= low) { return false; } } } if (high != null) { if (closedHigh) { //unreachable code as closedHigh is never set to true anywhere if (d > high) { return false; } } else { if (d >= high) { return false; } } } return true; } /** * * @return a String representation of the DoubleRange * @should print the range if high and low are not null and not infinite * @should print empty high if high is infinite * @should print empty low if low is infinite * @should print empty string if low and high are infinite */ @Override public String toString() { StringBuilder ret = new StringBuilder(); if (low != null && low.doubleValue() != Double.NEGATIVE_INFINITY) { ret.append(">"); if (closedLow) { ret.append("="); } ret.append(" " + Format.format(low)); if (high != null && high.doubleValue() != Double.NEGATIVE_INFINITY) { //BUG: should not append this if high is also infinite ret.append(" and "); } } if (high != null && high.doubleValue() != Double.POSITIVE_INFINITY) { ret.append("<"); if (closedHigh) { ret.append("="); } ret.append(" " + Format.format(high)); } return ret.toString(); } @Override public boolean equals(Object o) { if (o instanceof DoubleRange) { DoubleRange other = (DoubleRange) o; return low.equals(other.low) && high.equals(other.high); } return false; } /** * @should return the same hashCode for objects representing the same interval */ @Override public int hashCode() { return new HashCodeBuilder().append(low).append(high).build(); } }