Index: /Users/edwin/workspace/groovy/src/main/groovy/lang/IntRange.java =================================================================== --- /Users/edwin/workspace/groovy/src/main/groovy/lang/IntRange.java (revision 4080) +++ /Users/edwin/workspace/groovy/src/main/groovy/lang/IntRange.java (working copy) @@ -46,25 +46,110 @@ package groovy.lang; import java.util.AbstractList; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import javax.naming.OperationNotSupportedException; + +import org.codehaus.groovy.runtime.DefaultGroovyMethods; import org.codehaus.groovy.runtime.InvokerHelper; import org.codehaus.groovy.runtime.IteratorClosureAdapter; /** - * Represents a list of Integer objects from a specified int up to and including - * a given and to. + * Represents a list of Integer objects from a specified int up (or down) to and including + * a given to.

* + * This class is a copy of {@link ObjectRange} optimized for int. If you make any + * changes to this class, you might consider making parallel changes to {@link ObjectRange}. + * * @author James Strachan * @version $Revision$ */ public class IntRange extends AbstractList implements Range { + /** + * Iterates through each number in an IntRange. + */ + private class IntRangeIterator implements Iterator { + /** + * Counts from 0 up to size - 1. + */ + int index = 0; + + /** + * The number of values in the range. + */ + int size = size(); + + /** + * The next value to return. + */ + int value = (reverse) ? to : from; + + /** + * {@inheritDoc} + */ + public boolean hasNext() { + return index < size; + } + + /** + * {@inheritDoc} + */ + public Object next() { + if (index++ > 0) { + if (index > size) { + return null; + } + else { + if (reverse) { + --value; + } + else { + ++value; + } + } + } + return new Integer(value); + } + + /** + * Not supported. + * + * @throws OperationNotSupportedException always + */ + public void remove() { + IntRange.this.remove(index); + } + } + + /** + * The first number in the range. from is always less than or equal to to. + */ private int from; + + /** + * The last number in the range. to is always greater than or eqaul to from. + */ private int to; + + /** + * If false, counts up from from to to. Otherwise, counts down + * from to to from. + */ private boolean reverse; + /** + * Creates a new IntRange. If from is greater + * than to, a reverse range is created with + * from and to swapped. + * + * @param from + * the first number in the range. + * @param to + * the last number in the range. + */ public IntRange(int from, int to) { if (from > to) { this.from = to; @@ -77,25 +162,77 @@ } } - protected IntRange(int from, int to, boolean reverse) { + /** + * Creates a new IntRange. + * + * @param from + * the first value in the range. + * @param to + * the last value in the range. + * @param reverse + * true if the range should count from + * to to from. + * + * @throws IllegalArgumentException + * if from is greater than to. + */ + protected IntRange(int from, int to, boolean reverse) { + if (from > to) { + throw new IllegalArgumentException("'from' must be less than or equal to 'to'"); + } + this.from = from; this.to = to; this.reverse = reverse; } + /** + * Determines if this object is equal to another object. Delegates to + * {@link AbstractList#equals(Object)} if that is anthing + * other than an {@link IntRange}. + *

+ * + * It is not necessary to override hashCode, as + * {@link AbstractList#hashCode()} provides a suitable hash code.

+ * + * Note that equals is generally handled by {@link DefaultGroovyMethods#equals(List, List)} instead of this + * method. + * + * @param that + * the object to compare + * + * @return true if the objects are equal + */ public boolean equals(Object that) { if (that instanceof IntRange) { return equals((IntRange) that); } - else if (that instanceof List) { + if (that instanceof List) { return equals((List) that); } return false; } + /** + * Compares an IntRange to another IntRange. + * + * @return true if the ranges are equal + */ + public boolean equals(IntRange that) { + return that != null && this.reverse == that.reverse && this.from == that.from && this.to == that.to; + } + + /** + * Compares this range to a {@link List}. + * + * @param that + * the {@link List} to which to compare. + * + * @return true if the objects are equal. + */ public boolean equals(List that) { int size = size(); - if (that.size() == size) { + if (that != null && that.size() == size) { for (int i = 0; i < size; i++) { if (!InvokerHelper.compareEqual(get(i), that.get(i))) { return false; @@ -106,30 +243,54 @@ return false; } - public boolean equals(IntRange that) { - return this.reverse == that.reverse && this.from == that.from && this.to == that.to; - } - + /** + * Gets the 'from' value. + * + * @return the 'from' value. + */ public Comparable getFrom() { return new Integer(from); } + /** + * Gets the 'to' value. + * + * @return the 'to' value. + */ public Comparable getTo() { return new Integer(to); } + /** + * Gets the 'from' value as an integer. + * + * @return the 'from' value as an integer. + */ public int getFromInt() { return from; } + /** + * Gets the 'to' value as an integer. + * + * @return the 'to' value as an integer. + */ public int getToInt() { return to; } + /** + * Indicates whether this range counts down or up. + * + * @return true if this range counts down and false otherwise. + */ public boolean isReverse() { return reverse; } + /** + * {@inheritDoc} + */ public Object get(int index) { if (index < 0) { throw new IndexOutOfBoundsException("Index: " + index + " should not be negative"); @@ -141,47 +302,30 @@ return new Integer(value); } + /** + * {@inheritDoc} + */ public int size() { return to - from + 1; } - public int hashCode() { - return from ^ to + (reverse ? 1 : 0); - } + /** + * {@inheritDoc} + */ +// public int hashCode() { +// return from ^ to + (reverse ? 1 : 0); +// } + /** + * {@inheritDoc} + */ public Iterator iterator() { - return new Iterator() { - int index = 0; - int size = size(); - int value = (reverse) ? to : from; - - public boolean hasNext() { - return index < size; - } - - public Object next() { - if (index++ > 0) { - if (index > size) { - return null; - } - else { - if (reverse) { - --value; - } - else { - ++value; - } - } - } - return new Integer(value); - } - - public void remove() { - IntRange.this.remove(index); - } - }; + return new IntRangeIterator(); } + /** + * {@inheritDoc} + */ public List subList(int fromIndex, int toIndex) { if (fromIndex < 0) { throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); @@ -192,29 +336,53 @@ if (fromIndex > toIndex) { throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); } + + if (fromIndex == toIndex) { + return new ArrayList(); + } + return new IntRange(fromIndex + this.from, toIndex + this.from - 1, reverse); } + /** + * {@inheritDoc} + */ public String toString() { return (reverse) ? "" + to + ".." + from : "" + from + ".." + to; } + /** + * {@inheritDoc} + */ public String inspect() { return toString(); } + /** + * {@inheritDoc} + */ public boolean contains(Object value) { if (value instanceof Integer) { Integer integer = (Integer) value; int i = integer.intValue(); return i >= from && i <= to; - } else if (value instanceof IntRange) { + } + else if (value instanceof IntRange) { IntRange range = (IntRange) value; - return from<=range.from && range.to<=to; + return from <= range.from && range.to <= to; } return false; } + /** + * Steps through the range, calling a closure for each number. + * + * @param step + * the amount by which to step. If negative, steps through the + * range backwards. + * @param closure + * the closure to call + */ public void step(int step, Closure closure) { if (reverse) { step = -step; @@ -235,6 +403,16 @@ } } + /** + * Forms a list by stepping through the range by the indicated interval. + * + * @param step + * the amount by which to step. If negative, steps through the + * range backwards. + * + * @return the list formed by stepping through the range by the indicated + * interval. + */ public List step(int step) { IteratorClosureAdapter adapter = new IteratorClosureAdapter(this); step(step, adapter);