Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/366#discussion_r70736954
  
    --- Diff: src/main/groovy/lang/NumberRange.java ---
    @@ -0,0 +1,536 @@
    +/*
    + * 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.InvokerHelper;
    +import org.codehaus.groovy.runtime.IteratorClosureAdapter;
    +
    +import java.math.BigDecimal;
    +import java.math.BigInteger;
    +import java.util.AbstractList;
    +import java.util.Iterator;
    +import java.util.List;
    +
    +import static 
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareEqual;
    +import static 
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareGreaterThan;
    +import static 
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareGreaterThanEqual;
    +import static 
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareLessThan;
    +import static 
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareLessThanEqual;
    +import static 
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareNotEqual;
    +import static org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareTo;
    +import static org.codehaus.groovy.runtime.dgmimpl.NumberNumberMinus.minus;
    +import static org.codehaus.groovy.runtime.dgmimpl.NumberNumberPlus.plus;
    +import static 
org.codehaus.groovy.runtime.dgmimpl.NumberNumberMultiply.multiply;
    +
    +/**
    + * Represents an inclusive list of Numbers from a value to a value with a 
particular step size.
    + */
    +public class NumberRange extends AbstractList<Comparable> implements 
Range<Comparable> {
    +
    +    /**
    +     * The first value in the range.
    +     */
    +    private final Comparable from;
    +
    +    /**
    +     * The last value in the range.
    +     */
    +    private final Comparable to;
    +
    +    /**
    +     * The step size in the range.
    +     */
    +    private final Number stepSize;
    +
    +    /**
    +     * The cached size, or -1 if not yet computed
    +     */
    +    private int size = -1;
    +
    +    /**
    +     * <code>true</code> if the range counts backwards from 
<code>to</code> to <code>from</code>.
    +     */
    +    private final boolean reverse;
    +
    +    /**
    +     * <code>true</code> if the range includes the upper bound.
    +     */
    +    private final boolean inclusive;
    +
    +    /**
    +     * Creates an inclusive {@link NumberRange} with step size 1.
    +     * Creates a reversed range if <code>from</code> &lt; <code>to</code>.
    +     *
    +     * @param from the first value in the range
    +     * @param to   the last value in the range
    +     */
    +    public <T extends Number & Comparable, U extends Number & Comparable>
    +    NumberRange(T from, U to) {
    +        this(from, to, null, true);
    +    }
    +
    +    /**
    +     * Creates a new {@link NumberRange} with step size 1.
    +     * Creates a reversed range if <code>from</code> &lt; <code>to</code>.
    +     *
    +     * @param from start of the range
    +     * @param to   end of the range
    +     * @param inclusive whether the range is inclusive
    +     */
    +    public <T extends Number & Comparable, U extends Number & Comparable>
    +    NumberRange(T from, U to, boolean inclusive) {
    +        this(from, to, null, inclusive);
    +    }
    +
    +    /**
    +     * Creates an inclusive {@link NumberRange}.
    +     * Creates a reversed range if <code>from</code> &lt; <code>to</code>.
    +     *
    +     * @param from start of the range
    +     * @param to   end of the range
    +     * @param stepSize the gap between discrete elements in the range
    +     */
    +    public <T extends Number & Comparable, U extends Number & Comparable, 
V extends
    +            Number & Comparable<? super Number>>
    +    NumberRange(T from, U to, V stepSize) {
    +        this(from, to, stepSize, true);
    +    }
    +
    +    /**
    +     * Creates a {@link NumberRange}.
    +     * Creates a reversed range if <code>from</code> &lt; <code>to</code>.
    +     *
    +     * @param from start of the range
    +     * @param to   end of the range
    +     * @param stepSize the gap between discrete elements in the range
    +     * @param inclusive whether the range is inclusive
    +     */
    +    public <T extends Number & Comparable, U extends Number & Comparable, 
V extends
    +            Number & Comparable>
    +    NumberRange(T from, U to, V stepSize, boolean inclusive) {
    +        if (from == null) {
    +            throw new IllegalArgumentException("Must specify a non-null 
value for the 'from' index in a Range");
    +        }
    +        if (to == null) {
    +            throw new IllegalArgumentException("Must specify a non-null 
value for the 'to' index in a Range");
    +        }
    +        reverse = areReversed(from, to);
    +        Number tempFrom;
    +        Number tempTo;
    +        if (reverse) {
    +            tempFrom = to;
    +            tempTo = from;
    +        } else {
    +            tempFrom = from;
    +            tempTo = to;
    +        }
    +        if (tempFrom instanceof Short) {
    +            tempFrom = tempFrom.intValue();
    +        } else if (tempFrom instanceof Float) {
    +            tempFrom = tempFrom.doubleValue();
    +        }
    +        if (tempTo instanceof Short) {
    +            tempTo = tempTo.intValue();
    +        } else if (tempTo instanceof Float) {
    +            tempTo = tempTo.doubleValue();
    +        }
    +
    +        if (tempFrom instanceof Integer && tempTo instanceof Long) {
    +            tempFrom = tempFrom.longValue();
    +        } else if (tempTo instanceof Integer && tempFrom instanceof Long) {
    +            tempTo = tempTo.longValue();
    +        }
    +
    +        this.from = (Comparable) tempFrom;
    +        this.to = (Comparable) tempTo;
    +        this.stepSize = stepSize == null ? 1 : stepSize;
    +        this.inclusive = inclusive;
    +    }
    +
    +    /**
    +     * For a NumberRange with step size 1, creates a new NumberRange with 
the same
    +     * <code>from</code> and <code>to</code> as this NumberRange
    +     * but with a step size of <code>stepSize</code>.
    +     *
    +     * @param stepSize the desired step size
    +     * @return a new NumberRange
    +     */
    +    public <T extends Number & Comparable> NumberRange by(T stepSize) {
    +        if (!Integer.valueOf(1).equals(this.stepSize)) {
    +            throw new IllegalStateException("by only allowed on ranges 
with original stepSize = 1 but found " + this.stepSize);
    +        }
    +        return new NumberRange(comparableNumber(from), 
comparableNumber(to), stepSize, inclusive);
    +    }
    +
    +    @SuppressWarnings("unchecked")
    +    /* package private */ static <T extends Number & Comparable> T 
comparableNumber(Comparable c) {
    +        return (T) c;
    +    }
    +
    +    @SuppressWarnings("unchecked")
    +    /* package private */ static <T extends Number & Comparable> T 
comparableNumber(Number n) {
    +        return (T) n;
    +    }
    +
    +    private static boolean areReversed(Number from, Number to) {
    +        try {
    +            return compareGreaterThan(from, to);
    +        } catch (ClassCastException cce) {
    +            throw new IllegalArgumentException("Unable to create range due 
to incompatible types: " + from.getClass().getSimpleName() + ".." + 
to.getClass().getSimpleName() + " (possible missing brackets around range?)", 
cce);
    +        }
    +    }
    +
    +    public boolean equals(Object that) {
    +        return (that instanceof NumberRange) ? equals((NumberRange) that) 
: super.equals(that);
    +    }
    +
    +    /**
    +     * Compares an {@link NumberRange} to another {@link NumberRange}.
    +     *
    +     * @param that the object to check equality with
    +     * @return <code>true</code> if the ranges are equal
    +     */
    +    public boolean equals(NumberRange that) {
    --- End diff --
    
    I think it should be possible to have a streamlined calculation for the 
fast-path cases in size(). I'll look into that.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastruct...@apache.org or file a JIRA ticket
with INFRA.
---

Reply via email to