1:  package de.luschny.math.util;
   2:   
   3:  /**
   4:   * A PositiveRange is an interval of integers, given by a lower bound L and an
   5:   * upper bound U, such that 0 <= L and L <= U. A PositiveRange is immutable.
   6:   */
   7:   
   8:  public final class PositiveRange implements Cloneable
   9:  {
  10:   
  11:      private final int min;
  12:      private final int max;
  13:   
  14:      /**
  15:       * Creates a PositiveRange, i.e. a range of integers, such that 0 <= low <=
  16:       * high.
  17:       * 
  18:       * @param low
  19:       *            The low bound (minimum) of the range.
  20:       * @param high
  21:       *            The high bound (maximum) of the range.
  22:       * @throws IllegalArgumentException
  23:       */
  24:   
  25:      public PositiveRange(final int low, final int high)
  26:      {
  27:          if (!(0 <= low && low <= high))
  28:          {
  29:              // Yes, we force the arguments to be ordered
  30:              // to make the calling code more readable.
  31:              throw new IllegalArgumentException(new StringBuffer(64).append("The condition 0 <= ").append(low).append(
  32:                      " <= ").append(high).append(" is  false.").toString());
  33:          }
  34:   
  35:          this.min = low;
  36:          this.max = high;
  37:      }
  38:   
  39:      /**
  40:       * Creates and returns a copy of this object.
  41:       * 
  42:       * @return A copy of this PositiveRange.
  43:       */
  44:   
  45:      @Override
  46:      public Object clone()
  47:      {
  48:          try
  49:          {
  50:              return super.clone();
  51:          }
  52:          catch (CloneNotSupportedException e)
  53:          {
  54:              throw new InternalError(e.toString());
  55:          }
  56:      }
  57:   
  58:      /**
  59:       * Get the lower bound (minimum) of the range.
  60:       * 
  61:       * @return The minimum of the range.
  62:       */
  63:   
  64:      public int getMin()
  65:      {
  66:          return min;
  67:      }
  68:   
  69:      /**
  70:       * Get upper bound (maximum) of the range.
  71:       * 
  72:       * @return The maximum of the range.
  73:       */
  74:   
  75:      public int getMax()
  76:      {
  77:          return max;
  78:      }
  79:   
  80:      /**
  81:       * <p>
  82:       * Gets the range as a <code>String</code>.
  83:       * </p>
  84:       * <p>
  85:       * The format of the String is '[min, max]'.
  86:       * </p>
  87:       * 
  88:       * @return the <code>String</code> representation of this range.
  89:       */
  90:   
  91:      @Override
  92:      public String toString()
  93:      {
  94:          return new StringBuffer(32).append('[').append(min).append(',').append(max).append(']').toString();
  95:      }
  96:   
  97:      /**
  98:       * Checks, if the given value lies within the range, i.e. min &lt;= value
  99:       * and value &lt;= max.
 100:       * 
 101:       * @param value
 102:       *            The value to checked.
 103:       * @return True, if the range includes the value, false otherwise.
 104:       * @see PositiveRange#containsOrFail(int value)
 105:       */
 106:   
 107:      public boolean contains(final int value)
 108:      {
 109:          return min <= value && value <= max;
 110:      }
 111:   
 112:      /**
 113:       * Checks, if the given value lies within the range, i.e. min &lt;= value
 114:       * and value &lt;= max. If the value is not contained an
 115:       * IndexOutOfBoundsException will be raised.
 116:       * 
 117:       * @param value
 118:       *            The value to checked.
 119:       * @return True, if the range includes the value, false otherwise.
 120:       * @throws IndexOutOfBoundsException
 121:       */
 122:   
 123:      public boolean containsOrFail(final int value)
 124:      {
 125:          if (!(min <= value && value <= max))
 126:          {
 127:              throw new IndexOutOfBoundsException(new StringBuffer(64).append(this.toString()).append(
 128:                      " does not contain ").append(value).toString());
 129:          }
 130:          return true;
 131:      }
 132:   
 133:      /**
 134:       * Checks, if the given range is a subrange, i.e. this.min &lt;= range.min
 135:       * and range.max &lt;= this.max.
 136:       * 
 137:       * @param range
 138:       *            The range to be checked.
 139:       * @return True, if the given range lies within this range, false otherwise.
 140:       * @see PositiveRange#containsOrFail(PositiveRange range)
 141:       */
 142:   
 143:      public boolean contains(final PositiveRange range)
 144:      {
 145:          return min <= range.min && range.max <= max;
 146:      }
 147:   
 148:      /**
 149:       * Checks, if the given range is a subrange, i.e. this.min &lt;= range.min
 150:       * and range.max &lt;= this.max. If the range is not contained an
 151:       * IndexOutOfBoundsException will be raised.
 152:       * 
 153:       * @param range
 154:       *            The range to be checked.
 155:       * @return True, if the given range lies within this range, otherwise an
 156:       *         IndexOutOfBoundsException is thrown.
 157:       * @throws IndexOutOfBoundsException
 158:       */
 159:   
 160:      public boolean containsOrFail(final PositiveRange range)
 161:      {
 162:          if (!(min <= range.min && range.max <= max))
 163:          {
 164:              throw new IndexOutOfBoundsException(new StringBuffer(64).append(this.toString()).append(
 165:                      " does not contain ").append(range.toString()).toString());
 166:          }
 167:          return true;
 168:      }
 169:   
 170:      /**
 171:       * Computes the size of the range.
 172:       * 
 173:       * @return The size of the range.
 174:       */
 175:   
 176:      public int size()
 177:      {
 178:          return max - min + 1;
 179:      }
 180:   
 181:      /**
 182:       * Compares this range to the specified object. The result is true if and
 183:       * only if the argument is not null and is an range object that has the same
 184:       * bound values as this object.
 185:       * 
 186:       * @param o
 187:       *            The object to compare with.
 188:       * @return True if the objects are the same; false otherwise.
 189:       */
 190:   
 191:      @Override
 192:      public boolean equals(Object o)
 193:      {
 194:          if (this == o)
 195:          {
 196:              return true;
 197:          }
 198:          if (!(o instanceof PositiveRange))
 199:          {
 200:              return false;
 201:          }
 202:   
 203:          PositiveRange positiveRange = (PositiveRange) o;
 204:   
 205:          if (max != positiveRange.max)
 206:          {
 207:              return false;
 208:          }
 209:          return min == positiveRange.min;
 210:   
 211:      }
 212:   
 213:      /**
 214:       * A hash code value for this range.
 215:       * 
 216:       * @return Returns a hash code for this.
 217:       */
 218:   
 219:      @Override
 220:      public int hashCode()
 221:      {
 222:          return 29 * min + max;
 223:      }
 224:  }