// Copyright 2001-2002 by Steven McDougall. // This class is free software. // You can redistribute it and/or modify it under the terms of // either // - the GNU General Public License at http://www.gnu.org/licenses/gpl.html // - the Artistic License at http://www.perl.com/language/misc/Artistic.html package Set; public class IntSpan implements Cloneable { public static String emptyString = "-"; boolean negInf; boolean posInf; IntList edges; public IntSpan() { negInf = false; posInf = false; edges = new IntList(); } public IntSpan(String runList) { this(); runList = StripWhitespace(runList); if (runList.equals("-")) return; // empty set; if (runList.equals("(-)")) { negInf = true; posInf = true; return; // Z } java.util.StringTokenizer st = new java.util.StringTokenizer(runList, ","); while (st.hasMoreTokens()) { String run = st.nextToken(); if (run.startsWith("(-")) addOpenNeg(run); else if (run.endsWith("-)")) addOpenPos(run); else if (run.indexOf('-', 1)<0) addSingle (run); else addDouble (run); } } private String StripWhitespace(String s) { StringBuffer sb = new StringBuffer(); java.util.StringTokenizer st = new java.util.StringTokenizer(s); while (st.hasMoreTokens()) sb.append(st.nextToken()); return sb.toString(); } private void addOpenNeg(String run) { negInf = true; edges.add(run.substring(2)); } private void addOpenPos(String run) { int dash = run.lastIndexOf('-'); if (dash > -1) run = run.substring(0, dash); int lower = Integer.parseInt(run); boolean lGap = edges.size()==0 || lower-1 - edges.getI(-1) > 0; if (lGap) edges.add(lower-1); else edges.pop(); posInf = true; } private void addSingle(String run) { int upper = Integer.parseInt(run); addClosed(upper, upper); } private void addDouble(String run) { int pos = run.indexOf('-', 1); String st = run.substring(0, pos); int lower = Integer.parseInt(st); st = run.substring(pos+1); int upper = Integer.parseInt(st); addClosed(lower, upper); } private void addClosed(int lower, int upper) { boolean lGap = edges.size()==0 || lower-1 - edges.getI(-1) > 0; if (lGap) edges.add(lower-1); else edges.pop(); edges.add(upper); } public IntSpan(int[] elements) { this(); int[] element = new int[elements.length]; System.arraycopy(elements, 0, element, 0, elements.length); java.util.Arrays.sort(element); for (int i=0; i=0) topEdge = edges.getI(top); if (top>=0 && topEdge==element[i]) continue; // skip duplicates if (top>=0 && topEdge==element[i]-1) { edges.set(top, element[i]); } else { edges.add(element[i]-1); edges.add(element[i] ); } } } public Object clone() { IntSpan clone = new IntSpan(); clone.negInf = negInf; clone.posInf = posInf; clone.edges = (IntList)(edges.clone()); return clone; } public String toString() { return runList(); } public String runList() { if (empty()) return emptyString; if (universal()) return "(-)"; StringBuffer sb = new StringBuffer(); int i = 0; if (negInf) { int upper = edges.getI(0); sb.append("(-" + Integer.toString(upper)); i = 1; } while (i < edges.size()-1) { if (i>0) sb.append(","); int lower = edges.getI(i ); int upper = edges.getI(i+1); if (lower+1==upper) sb.append(Integer.toString(upper)); else sb.append(Integer.toString(lower+1) + "-" + Integer.toString(upper)); i += 2; } if (posInf) { if (i > 0) sb.append(","); int lower = edges.getI(i); sb.append(Integer.toString(lower+1) + "-)"); } return sb.toString(); } public int[] elements() { if (negInf || posInf) return null; int[] list = new int[cardinality()]; int l = 0; for (int i=0; i 0; boolean rGap = i==edges.size() || edges.getI(i) - n > 0; if ( lGap && rGap) { edges.add(i, n ); edges.add(i, n-1); } else if (!lGap && rGap) { edges.inc(i-1); } else if ( lGap && !rGap) { edges.dec(i ); } else { edges.remove(i-1); edges.remove(i-1); } } public void remove(int n) { boolean inSet = negInf; int i; for (i=0; i 0; boolean rGap = i==edges.size() || edges.getI(i) - n > 0; if ( lGap && rGap) { edges.add(i, n ); edges.add(i, n-1); } else if (!lGap && rGap) { edges.inc(i-1); } else if ( lGap && !rGap) { edges.dec(i ); } else { edges.remove(i-1); edges.remove(i-1); } } public Integer min() { return empty() || negInf ? null : new Integer(edges.getI((0))+1); } public Integer max() { int i = edges.size()-1; return empty() || posInf ? null : new Integer(edges.getI(i)); } public static interface Testable { boolean test(int n); } public IntSpan grep(Testable predicate) { if (infinite()) return null; IntSpan s = new IntSpan(); for (int i=0; i0 && n <= edges.getI(-1); } public boolean hasPrevious() { return negInf || edges.size()>0 && edges.getI(0) < n; } public Object next() { if (!hasNext()) throw new java.util.NoSuchElementException("Set.IntSpan.Iterator.next"); int nEdges = edges.size(); if (iHi < nEdges && n <= edges.getI(iHi) || nEdges <= iHi) { Integer i = new Integer(n); nRemove = n; n++; return i; } iLo += 2; iHi += 2; n = edges.getI(iLo) + 1; nRemove = n; return new Integer(n); } public Object previous() { if (!hasPrevious()) throw new java.util.NoSuchElementException("Set.IntSpan.Iterator.previous"); int nEdges = edges.size(); if (iLo < 0 || 0 <= iLo && iLo < nEdges && edges.getI(iLo) < n) { Integer i = new Integer(n); nRemove = n; n--; return i; } iLo -= 2; iHi -= 2; n = edges.getI(iHi); nRemove = n; return new Integer(n); } public void remove() { } public String toString() { return (new Integer(n)).toString(); } } } class IntList extends java.util.ArrayList implements Cloneable { void add(int n) { add(new Integer(n)); } void add(int i, int n) { add(i, new Integer(n)); } void add(String s) { add(new Integer(s)); } void set(int i, int n) { set(i, new Integer(n)); } int getI(int i) { if (i<0) i += size(); return ((Integer)get(i)).intValue(); } void inc(int i) { int n = ((Integer)get(i)).intValue(); set(i, new Integer(n+1)); } void dec(int i) { int n = ((Integer)get(i)).intValue(); set(i, new Integer(n-1)); } void pop() { int i = size(); if (i>0) remove(i-1); } public Object clone() { IntList clone = new IntList(); for (int i=0; i