All Downloads are FREE. Search and download functionalities are using the official Maven repository.

groovy.lang.IntRange Maven / Gradle / Ivy

The newest version!
/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 */
package groovy.lang;

import org.codehaus.groovy.runtime.IteratorClosureAdapter;
import org.codehaus.groovy.runtime.RangeInfo;

import java.math.BigInteger;
import java.util.AbstractList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

/**
 * 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}. * Instances of this class may be either inclusive aware or non-inclusive aware. See the * relevant constructors for creating each type. Inclusive aware IntRange instances are * suitable for use with Groovy's range indexing - in particular if the from or to values * might be negative. This normally happens underneath the covers but is worth keeping * in mind if creating these ranges yourself explicitly. */ 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. */ private int index; /** * The number of values in the range. */ private int size = size(); /** * The next value to return. */ private int value = isReverse() ? getTo() : getFrom(); @Override public boolean hasNext() { return index < size; } @Override public Integer next() { if (!hasNext()) { // TODO instead of returning null, do this: throw new NoSuchElementException(); return null; } if (index++ > 0) { if (isReverse()) { --value; } else { ++value; } } return value; } /** * Not supported. * * @throws java.lang.UnsupportedOperationException * always */ @Override public void remove() { IntRange.this.remove(index); } } /** * For non-inclusive aware ranges, the first number in the range; from is always less than or equal to to. * For inclusive aware ranges, the from argument supplied to the constructor. */ private int from; /** * For non-inclusive aware ranges, the last number in the range; to is always greater than or equal to from. * For inclusive aware ranges, the from argument supplied to the constructor. */ private int to; /** * If false, counts up from from to to. Otherwise, counts down * from to to from. Not used for inclusive aware ranges. */ private boolean reverse; /** * If true, to is included in the range. Otherwise, the range stops * before the to value. Null for non-inclusive aware ranges. */ private Boolean inclusive; /** * Creates a new non-inclusive 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. * @throws IllegalArgumentException if the range would contain more than {@link Integer#MAX_VALUE} values. */ public IntRange(int from, int to) { this.inclusive = null; if (from > to) { this.from = to; this.to = from; this.reverse = true; } else { this.from = from; this.to = to; } checkSize(); } /** * Creates a new non-inclusive aware 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) { this.inclusive = null; if (from > to) { throw new IllegalArgumentException("'from' must be less than or equal to 'to'"); } this.from = from; this.to = to; this.reverse = reverse; checkSize(); } /** * Creates a new inclusive aware IntRange. * * @param from the first value in the range. * @param to the last value in the range. * @param inclusive true if the to value is included in the range. */ public IntRange(boolean inclusive, int from, int to) { this.from = from; this.to = to; this.inclusive = inclusive; this.reverse = false; // range may still be reversed, this value is ignored for inclusive-aware ranges checkSize(); } private void checkSize() { // size() in the Collection interface returns an integer, so ranges can have no more than Integer.MAX_VALUE elements final Long size = (long) to - from + 1; if (size > Integer.MAX_VALUE) { throw new IllegalArgumentException("A range must have no more than " + Integer.MAX_VALUE + " elements but attempted " + size + " elements"); } } /** * A method for determining from and to information when using this IntRange to index an aggregate object of the specified size. * Normally only used internally within Groovy but useful if adding range indexing support for your own aggregates. * * @param size the size of the aggregate being indexed * @return the calculated range information (with 1 added to the to value, ready for providing to subList */ public RangeInfo subListBorders(int size) { if (inclusive == null) { throw new IllegalStateException("Should not call subListBorders on a non-inclusive aware IntRange"); } int tempFrom = from; if (tempFrom < 0) { tempFrom += size; } int tempTo = to; if (tempTo < 0) { tempTo += size; } if (tempFrom > tempTo) { return new RangeInfo(inclusive ? tempTo : tempTo + 1, tempFrom + 1, true); } return new RangeInfo(tempFrom, inclusive ? tempTo + 1 : tempTo, false); } /** * Determines if this object is equal to another object. Delegates to * {@link AbstractList#equals(Object)} if that is anything * 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 org.codehaus.groovy.runtime.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) { return that instanceof IntRange ? equals((IntRange) that) : super.equals(that); } /** * Compares an {@link IntRange} to another {@link IntRange}. * * @param that the object to compare for equality * @return true if the ranges are equal */ public boolean equals(IntRange that) { return that != null && ((inclusive == null && reverse == that.reverse && from == that.from && to == that.to) || (inclusive != null && inclusive == that.inclusive && from == that.from && to == that.to)); } @Override public Integer getFrom() { if (inclusive == null || from <= to) { return from; } return inclusive ? to : to + 1; } @Override public Integer getTo() { if (inclusive == null) { return to; } if (from <= to) { return inclusive ? to : to - 1; } return from; } /** * Returns the inclusive flag. Null for non-inclusive aware ranges or non-null for inclusive aware ranges. */ public Boolean getInclusive() { return inclusive; } /** * Gets the 'from' value as a primitive integer. * * @return the 'from' value as a primitive integer. */ public int getFromInt() { return getFrom(); } /** * Gets the 'to' value as a primitive integer. * * @return the 'to' value as a primitive integer. */ public int getToInt() { return getTo(); } @Override public boolean isReverse() { return inclusive == null ? reverse : (from > to); } @Override public boolean containsWithinBounds(Object o) { return contains(o); } @Override public Integer get(int index) { if (index < 0) { throw new IndexOutOfBoundsException("Index: " + index + " should not be negative"); } if (index >= size()) { throw new IndexOutOfBoundsException("Index: " + index + " too big for range: " + this); } return isReverse() ? getTo() - index : index + getFrom(); } @Override public int size() { return getTo() - getFrom() + 1; } @Override public Iterator iterator() { return new IntRangeIterator(); } @Override public List subList(int fromIndex, int toIndex) { if (fromIndex < 0) { throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); } if (toIndex > size()) { throw new IndexOutOfBoundsException("toIndex = " + toIndex); } if (fromIndex > toIndex) { throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); } if (fromIndex == toIndex) { return new EmptyRange(getFrom()); } return new IntRange(fromIndex + getFrom(), toIndex + getFrom() - 1, isReverse()); } public String toString() { return inclusive != null ? ("" + from + ".." + (inclusive ? "" : "<") + to) : (reverse ? "" + to + ".." + from : "" + from + ".." + to); } @Override public String inspect() { return toString(); } @Override public boolean contains(Object value) { if (value instanceof Integer) { return (Integer) value >= getFrom() && (Integer) value <= getTo(); } if (value instanceof BigInteger) { final BigInteger bigint = (BigInteger) value; return bigint.compareTo(BigInteger.valueOf(getFrom())) >= 0 && bigint.compareTo(BigInteger.valueOf(getTo())) <= 0; } return false; } @Override public boolean containsAll(Collection other) { if (other instanceof IntRange) { final IntRange range = (IntRange) other; return getFrom() <= range.getFrom() && range.getTo() <= getTo(); } return super.containsAll(other); } @Override public void step(int step, Closure closure) { if (step == 0) { if (!getFrom().equals(getTo())) { throw new GroovyRuntimeException("Infinite loop detected due to step size of 0"); } return; // from == to and step == 0, nothing to do, so return } if (isReverse()) { step = -step; } if (step > 0) { int value = getFrom(); while (value <= getTo()) { closure.call(value); if(((long) value + step) >= Integer.MAX_VALUE) { break; } value = value + step; } } else { int value = getTo(); while (value >= getFrom()) { closure.call(value); if(((long) value + step) <= Integer.MIN_VALUE) { break; } value = value + step; } } } @Override public List step(int step) { final IteratorClosureAdapter adapter = new IteratorClosureAdapter(this); step(step, adapter); return adapter.asList(); } @Override public int hashCode(){ int hashCode; final int from = this.getFrom(); final int to = this.getTo(); hashCode = ((from+to+1)*(from+to))/2+to; return hashCode; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy