org.pshdl.model.simulation.RangeTool.java Source code

Java tutorial

Introduction

Here is the source code for org.pshdl.model.simulation.RangeTool.java

Source

/*******************************************************************************
 * PSHDL is a library and (trans-)compiler for PSHDL input. It generates
 *     output suitable for implementation or simulation of it.
 *
 *     Copyright (C) 2013 Karsten Becker (feedback (at) pshdl (dot) org)
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *     This License does not grant permission to use the trade names, trademarks,
 *     service marks, or product names of the Licensor, except as required for
 *     reasonable and customary use in describing the origin of the Work.
 *
 * Contributors:
 *     Karsten Becker - initial API and implementation
 ******************************************************************************/
package org.pshdl.model.simulation;

import java.math.BigInteger;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Range;

public class RangeTool {
    public static class RangeVal implements Comparable<RangeVal> {
        public final BigInteger value;
        public int count;

        public RangeVal(BigInteger value, int count) {
            super();
            this.value = value;
            this.count = count;
        }

        @Override
        public String toString() {
            return value + (isStart() ? "S" : "E") + count;
        }

        @Override
        public int compareTo(RangeVal o) {
            // Sort by value first
            final int v = value.compareTo(o.value);
            if (v != 0)
                return v;
            // Then sort Starts before ends
            return -count;
        }

        public boolean isStart() {
            return count > 0;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = (prime * result) + count;
            result = (prime * result) + ((value == null) ? 0 : value.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            final RangeVal other = (RangeVal) obj;
            if (count != other.count)
                return false;
            if (value == null) {
                if (other.value != null)
                    return false;
            } else if (!value.equals(other.value))
                return false;
            return true;
        }

    }

    /**
     * Sort a List of ranges by their number, then start/end and merge multiple
     * start/ends
     *
     * @param temp
     *            a list of RangeVal which can be unsorted
     */
    public static void preSort(List<RangeVal> temp) {
        Collections.sort(temp);
        RangeVal last = null;
        for (final Iterator<RangeVal> iterator = temp.iterator(); iterator.hasNext();) {
            final RangeVal rangeVal = iterator.next();
            if ((last != null) && last.value.equals(rangeVal.value) && (last.isStart() == rangeVal.isStart())) {
                iterator.remove();
                last.count += rangeVal.count;
            } else {
                last = rangeVal;
            }
        }
    }

    /**
     * Splits a list into ValueRange Objects that do not overlap each other, but
     * fully represent the ranges given by value
     *
     * @param value
     *            a list of RangeVal Objects that need to be split
     * @return
     */
    public static SortedSet<Range<BigInteger>> split(List<RangeVal> value) {
        preSort(value);
        final SortedSet<Range<BigInteger>> res = new TreeSet<Range<BigInteger>>(
                new Comparator<Range<BigInteger>>() {
                    @Override
                    public int compare(Range<BigInteger> arg0, Range<BigInteger> arg1) {
                        return ComparisonChain.start() //
                                .compare(arg0.lowerEndpoint(), arg1.lowerEndpoint()) //
                                .compare(arg0.upperEndpoint(), arg1.upperEndpoint()) //
                                .result();
                    }
                });
        RangeVal last = null;
        int count = 0;
        for (final RangeVal current : value) {
            if (last != null) {
                if (last.isStart()) {
                    if (current.isStart()) {
                        res.add(createRange(last.value, current.value.subtract(BigInteger.ONE)));
                    } else {
                        res.add(createRange(last.value, current.value));
                    }
                } else {
                    if (current.isStart()) {
                        if ((count > 0) && (current.value.subtract(last.value).compareTo(BigInteger.ONE) > 0)) {
                            res.add(createRange(last.value.add(BigInteger.ONE),
                                    current.value.subtract(BigInteger.ONE)));
                        }
                    } else {
                        res.add(createRange(last.value.add(BigInteger.ONE), current.value));
                    }
                }
            } else {
                if (!current.isStart())
                    throw new IllegalArgumentException("this should not happen");
            }
            count += current.count;
            last = current;
        }
        return res;
    }

    public static void main(String[] args) {
        validate(split(createRanges(6, 10, 5, 5, 0, 10)));
        validate(split(createRanges(1, 2, 5, 6)));
        validate(split(createRanges(1, 2, 5, 6, 1, 6)));
        // 5->8 9->10 11
        validate(split(createRanges(5, 8, 9, 10, 11, 11)));
        // 5, 6->7, 8, 9, 10
        validate(split(createRanges(5, 10, 6, 8, 8, 9)));
        validate(split(createRanges(5, 10, 6, 8, 8, 9, 6, 9)));
        validate(split(createRanges(5, 10, 6, 8, 8, 9, 6, 9, 6, 11, 8, 9)));
        validate(split(createRanges(5, 10, 6, 8, 8, 9, 6, 9, 6, 11, 8, 9, 14, 18)));
        validate(split(createRanges(7, 10, 5, 5, 6, 6, 7, 7)));
        validate(split(createRanges(2, 2, 7, 13, 7, 10, 5, 5, 6, 6, 7, 7, 5, 8, 10, 10)));
        validate(split(createRanges(7, 10, 5, 5, 6, 6, 7, 7, 5, 8)));
        validate(split(createRanges(7, 10, 5, 5, 6, 6, 7, 7, 5, 7)));
    }

    private static void validate(Set<Range<BigInteger>> split) {
        System.out.println("Result:" + split);
        Range<BigInteger> last = Range.closed(BigInteger.valueOf(-1), BigInteger.valueOf(-1));
        for (final Range<BigInteger> range : split) {
            if (range.isConnected(last))
                throw new IllegalArgumentException("Ranges are connected:" + last + " and " + range);
            last = range;
        }
    }

    private static List<RangeVal> createRanges(int... r) {
        final List<RangeVal> temp = new LinkedList<RangeVal>();
        for (int i = 0; i < r.length; i += 2) {
            temp.add(new RangeVal(BigInteger.valueOf(r[i]), 1));
            temp.add(new RangeVal(BigInteger.valueOf(r[i + 1]), -1));
            System.out.print("[" + r[i] + "," + r[i + 1] + "] ");
        }
        return temp;
    }

    public static Range<BigInteger> createRangeInt(int lower, int upper) {
        return createRange(BigInteger.valueOf(lower), BigInteger.valueOf(upper));
    }

    public static <C extends Comparable<C>> Range<C> createRange(C lower, C upper) {
        if (lower.compareTo(upper) > 0)
            return Range.closed(upper, lower);
        return Range.closed(lower, upper);
    }
}