001    /*
002     $Id: IntRange.java,v 1.11 2005/09/15 19:22:56 blackdrag Exp $
003    
004     Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005    
006     Redistribution and use of this software and associated documentation
007     ("Software"), with or without modification, are permitted provided
008     that the following conditions are met:
009    
010     1. Redistributions of source code must retain copyright
011        statements and notices.  Redistributions must also contain a
012        copy of this document.
013    
014     2. Redistributions in binary form must reproduce the
015        above copyright notice, this list of conditions and the
016        following disclaimer in the documentation and/or other
017        materials provided with the distribution.
018    
019     3. The name "groovy" must not be used to endorse or promote
020        products derived from this Software without prior written
021        permission of The Codehaus.  For written permission,
022        please contact info@codehaus.org.
023    
024     4. Products derived from this Software may not be called "groovy"
025        nor may "groovy" appear in their names without prior written
026        permission of The Codehaus. "groovy" is a registered
027        trademark of The Codehaus.
028    
029     5. Due credit should be given to The Codehaus -
030        http://groovy.codehaus.org/
031    
032     THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033     ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034     NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035     FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
036     THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041     STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043     OF THE POSSIBILITY OF SUCH DAMAGE.
044    
045     */
046    package groovy.lang;
047    
048    import java.util.AbstractList;
049    import java.util.Iterator;
050    import java.util.List;
051    
052    import org.codehaus.groovy.runtime.InvokerHelper;
053    import org.codehaus.groovy.runtime.IteratorClosureAdapter;
054    
055    /**
056     * Represents a list of Integer objects from a specified int up to and including
057     * a given and to.
058     * 
059     * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
060     * @version $Revision: 1.11 $
061     */
062    public class IntRange extends AbstractList implements Range {
063    
064        private int from;
065        private int to;
066        private boolean reverse;
067    
068        public IntRange(int from, int to) {
069            if (from > to) {
070                this.from = to;
071                this.to = from;
072                this.reverse = true;
073            }
074            else {
075                this.from = from;
076                this.to = to;
077            }
078        }
079    
080        protected IntRange(int from, int to, boolean reverse) {
081            this.from = from;
082            this.to = to;
083            this.reverse = reverse;
084        }
085    
086        public boolean equals(Object that) {
087            if (that instanceof IntRange) {
088                return equals((IntRange) that);
089            }
090            else if (that instanceof List) {
091                return equals((List) that);
092            }
093            return false;
094        }
095    
096        public boolean equals(List that) {
097            int size = size();
098            if (that.size() == size) {
099                for (int i = 0; i < size; i++) {
100                    if (!InvokerHelper.compareEqual(get(i), that.get(i))) {
101                        return false;
102                    }
103                }
104                return true;
105            }
106            return false;
107        }
108    
109        public boolean equals(IntRange that) {
110            return this.reverse == that.reverse && this.from == that.from && this.to == that.to;
111        }
112    
113        public Comparable getFrom() {
114            return new Integer(from);
115        }
116    
117        public Comparable getTo() {
118            return new Integer(to);
119        }
120    
121        public int getFromInt() {
122            return from;
123        }
124    
125        public int getToInt() {
126            return to;
127        }
128    
129        public boolean isReverse() {
130            return reverse;
131        }
132    
133        public Object get(int index) {
134            if (index < 0) {
135                throw new IndexOutOfBoundsException("Index: " + index + " should not be negative");
136            }
137            if (index >= size()) {
138                throw new IndexOutOfBoundsException("Index: " + index + " too big for range: " + this);
139            }
140            int value = (reverse) ? to - index : index + from;
141            return new Integer(value);
142        }
143    
144        public int size() {
145            return to - from + 1;
146        }
147    
148        public int hashCode() {
149            return from ^ to + (reverse ? 1 : 0);
150        }
151    
152        public Iterator iterator() {
153            return new Iterator() {
154                int index = 0;
155                int size = size();
156                int value = (reverse) ? to : from;
157    
158                public boolean hasNext() {
159                    return index < size;
160                }
161    
162                public Object next() {
163                    if (index++ > 0) {
164                        if (index > size) {
165                            return null;
166                        }
167                        else {
168                            if (reverse) {
169                                --value;
170                            }
171                            else {
172                                ++value;
173                            }
174                        }
175                    }
176                    return new Integer(value);
177                }
178    
179                public void remove() {
180                    IntRange.this.remove(index);
181                }
182            };
183        }
184    
185        public List subList(int fromIndex, int toIndex) {
186            if (fromIndex < 0) {
187                throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
188            }
189            if (toIndex > size()) {
190                throw new IndexOutOfBoundsException("toIndex = " + toIndex);
191            }
192            if (fromIndex > toIndex) {
193                throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
194            }
195            return new IntRange(fromIndex + this.from, toIndex + this.from - 1, reverse);
196        }
197    
198        public String toString() {
199            return (reverse) ? "" + to + ".." + from : "" + from + ".." + to;
200        }
201        
202        public String inspect() {
203            return toString();
204        }
205        
206        public boolean contains(Object value) {
207            if (value instanceof Integer) {
208                Integer integer = (Integer) value;
209                int i = integer.intValue();
210                return i >= from && i <= to;
211            } else if (value instanceof IntRange) {
212                IntRange range = (IntRange) value;
213                return from<=range.from && range.to<=to;
214            } 
215            return false;
216        }
217    
218        public void step(int step, Closure closure) {
219            if (reverse) {
220                step = -step;
221            }
222            if (step >= 0) {
223                int value = from;
224                while (value <= to) {
225                    closure.call(new Integer(value));
226                    value = value + step;
227                }
228            }
229            else {
230                int value = to;
231                while (value >= from) {
232                    closure.call(new Integer(value));
233                    value = value + step;
234                }
235            }
236        }
237    
238        public List step(int step) {
239            IteratorClosureAdapter adapter = new IteratorClosureAdapter(this);
240            step(step, adapter);
241            return adapter.asList();
242        }
243    }