/* [The "BSD licence"] Copyright (c) 2005-2006 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.*; /** 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()); } */ }