/* * [The "BSD license"] * Copyright (c) 2010 Terence Parr * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.antlr.misc; import org.antlr.analysis.Label; import org.antlr.tool.Grammar; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; /** A set of integers that relies on ranges being common to do * "run-length-encoded" like compression (if you view an IntSet like * a BitSet with runs of 0s and 1s). Only ranges are recorded so that * a few ints up near value 1000 don't cause massive bitsets, just two * integer intervals. * * element values may be negative. Useful for sets of EPSILON and EOF. * * 0..9 char range is index pair ['\u0030','\u0039']. * Multiple ranges are encoded with multiple index pairs. Isolated * elements are encoded with an index pair where both intervals are the same. * * The ranges are ordered and disjoint so that 2..6 appears before 101..103. */ public class IntervalSet implements IntSet { public static final IntervalSet COMPLETE_SET = IntervalSet.of(0,Label.MAX_CHAR_VALUE); /** The list of sorted, disjoint intervals. */ protected List intervals; /** Create a set with no elements */ public IntervalSet() { intervals = new ArrayList(2); // most sets are 1 or 2 elements } public IntervalSet(List intervals) { this.intervals = intervals; } /** Create a set with a single element, el. */ public static IntervalSet of(int a) { IntervalSet s = new IntervalSet(); s.add(a); return s; } /** Create a set with all ints within range [a..b] (inclusive) */ public static IntervalSet of(int a, int b) { IntervalSet s = new IntervalSet(); s.add(a,b); return s; } /** Add a single element to the set. An isolated element is stored * as a range el..el. */ public void add(int el) { add(el,el); } /** Add interval; i.e., add all integers from a to b to set. * If b 0 ) { IntervalSet s = IntervalSet.of(0, first.a-1); IntervalSet a = (IntervalSet)s.and(vocabularyIS); compl.addAll(a); } for (int i=1; i mine.b ) { // uh oh, right of theirs extends past right of mine // therefore could overlap with next of mine so don't // move theirs iterator yet moveTheirs = false; } // always move mine mine = null; if ( thisIter.hasNext() ) { mine = (Interval)thisIter.next(); } if ( moveTheirs ) { theirs = null; if ( otherIter.hasNext() ) { theirs = (Interval)otherIter.next(); } } } } } return diff; } */ /** TODO: implement this! */ public IntSet or(IntSet a) { IntervalSet o = new IntervalSet(); o.addAll(this); o.addAll(a); //throw new NoSuchMethodError(); return o; } /** Return a new set with the intersection of this set with other. Because * the intervals are sorted, we can use an iterator for each list and * just walk them together. This is roughly O(min(n,m)) for interval * list lengths n and m. */ public IntSet and(IntSet other) { if ( other==null ) { //|| !(other instanceof IntervalSet) ) { return null; // nothing in common with null set } ArrayList myIntervals = (ArrayList)this.intervals; ArrayList theirIntervals = (ArrayList)((IntervalSet)other).intervals; IntervalSet intersection = null; int mySize = myIntervals.size(); int theirSize = theirIntervals.size(); int i = 0; int j = 0; // iterate down both interval lists looking for nondisjoint intervals while ( i1 ) { buf.append("{"); } Iterator iter = this.intervals.iterator(); while (iter.hasNext()) { Interval I = (Interval) iter.next(); int a = I.a; int b = I.b; if ( a==b ) { if ( g!=null ) { buf.append(g.getTokenDisplayName(a)); } else { buf.append(a); } } else { if ( g!=null ) { buf.append(g.getTokenDisplayName(a)+".."+g.getTokenDisplayName(b)); } else { buf.append(a+".."+b); } } if ( iter.hasNext() ) { buf.append(", "); } } if ( this.intervals.size()>1 ) { buf.append("}"); } return buf.toString(); } public int size() { int n = 0; int numIntervals = intervals.size(); if ( numIntervals==1 ) { Interval firstInterval = this.intervals.get(0); return firstInterval.b-firstInterval.a+1; } for (int i = 0; i < numIntervals; i++) { Interval I = (Interval) intervals.get(i); n += (I.b-I.a+1); } return n; } public List toList() { List values = new ArrayList(); int n = intervals.size(); for (int i = 0; i < n; i++) { Interval I = (Interval) intervals.get(i); int a = I.a; int b = I.b; for (int v=a; v<=b; v++) { values.add(Utils.integer(v)); } } return values; } /** Get the ith element of ordered set. Used only by RandomPhrase so * don't bother to implement if you're not doing that for a new * ANTLR code gen target. */ public int get(int i) { int n = intervals.size(); int index = 0; for (int j = 0; j < n; j++) { Interval I = (Interval) intervals.get(j); int a = I.a; int b = I.b; for (int v=a; v<=b; v++) { if ( index==i ) { return v; } index++; } } return -1; } public int[] toArray() { int[] values = new int[size()]; int n = intervals.size(); int j = 0; for (int i = 0; i < n; i++) { Interval I = (Interval) intervals.get(i); int a = I.a; int b = I.b; for (int v=a; v<=b; v++) { values[j] = v; j++; } } return values; } public org.antlr.runtime.BitSet toRuntimeBitSet() { org.antlr.runtime.BitSet s = new org.antlr.runtime.BitSet(getMaxElement()+1); int n = intervals.size(); for (int i = 0; i < n; i++) { Interval I = (Interval) intervals.get(i); int a = I.a; int b = I.b; for (int v=a; v<=b; v++) { s.add(v); } } return s; } public void remove(int el) { throw new NoSuchMethodError("IntervalSet.remove() unimplemented"); } /* protected void finalize() throws Throwable { super.finalize(); System.out.println("size "+intervals.size()+" "+size()); } */ }