mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			437 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			437 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Java
		
	
	
	
/* SetOfIntegerSyntax.java --
 | 
						|
   Copyright (C) 2003, 2004, 2005  Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath 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 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath 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 GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
package javax.print.attribute;
 | 
						|
 | 
						|
import java.io.Serializable;
 | 
						|
import java.text.CharacterIterator;
 | 
						|
import java.text.StringCharacterIterator;
 | 
						|
import java.util.ArrayList;
 | 
						|
import java.util.Arrays;
 | 
						|
import java.util.Comparator;
 | 
						|
 | 
						|
/**
 | 
						|
 * <code>SetOfIntegerSyntax</code> is the abstract base class of all attribute
 | 
						|
 * classes which provide a set of non-negative integers as value (e.g. the
 | 
						|
 * page ranges to print) represented as single values or ranges of values.
 | 
						|
 * <p>
 | 
						|
 * A <code>SetOfIntegerSyntax</code> instance consists of an integer array of
 | 
						|
 * ranges. Ranges may have the same lower and upper bound representing a single
 | 
						|
 * integer value. Ranges with a lower bound greater than the upper bound are
 | 
						|
 * null ranges and discarded. Ranges may overlap in their values. In no case
 | 
						|
 * negative integers are allowed.
 | 
						|
 * </p>
 | 
						|
 * <p>
 | 
						|
 * There are several constructors available:
 | 
						|
 * <ul>
 | 
						|
 * <li><code>SetOfIntegerSyntax(int member)</code><br>
 | 
						|
 * Constructor for an instance with only one integer value.
 | 
						|
 * </li><br>
 | 
						|
 * <li><code>SetOfIntegerSyntax(int lowerBound, int upperBound)</code><br>
 | 
						|
 * Constructor for an instance with one range of integer values.
 | 
						|
 * </li><br>
 | 
						|
 * <li><code>SetOfIntegerSyntax(int[][] members)</code><br>
 | 
						|
 * Flexible constructor for an instance with several single integer values
 | 
						|
 * and/or several ranges of integer values. The allowed array form is an
 | 
						|
 * array of integer arrays of length one or two. Examples are:
 | 
						|
 * <code>int[0][]</code> for empty set of integers, <code>int[][] {{1}}</code>
 | 
						|
 * , <code>int[][] {{1,5}}</code>, <code>int[][] {{1,5},{7,9}}</code>,
 | 
						|
 * <code>int[][] {{3,7},{19}}</code>.
 | 
						|
 * </li><br>
 | 
						|
 * <li><code>SetOfIntegerSyntax(String s)</code><br>
 | 
						|
 * Flexible constructor for an instance with several single integer values
 | 
						|
 * and/or several ranges of integer values. The allowed String instance have
 | 
						|
 * to be a String with comma separated ranges of integer values or single
 | 
						|
 * values. Ranges are represented by two integer with a hypen (-) or colon (:)
 | 
						|
 * between the lower and upper bound value. Whitespace characters are ignored.
 | 
						|
 * Examples are: <code>""</code> for an empty set of integers,
 | 
						|
 * <code>"1"</code>, <code>"1-5"</code>, <code>"1-5,7-9"</code>,
 | 
						|
 * <code>"3-7,19"</code> and <code>"1:2,4"</code>.
 | 
						|
 * </li>
 | 
						|
 * </ul>
 | 
						|
 * </p>
 | 
						|
 * <p>
 | 
						|
 * <b>Internal storage:</b><br>
 | 
						|
 * The set of integers are stored internally in a normalized array form.
 | 
						|
 * In the normalized array form the set of integer ranges are represented
 | 
						|
 * in as few ranges as possible and overlapping ranges are merged. The ranges
 | 
						|
 * are always represented as an integer array of length two with ranges
 | 
						|
 * stored in {lower bound, upper bound} form. The ranges are stored in
 | 
						|
 * ascending order, without any null ranges.
 | 
						|
 * </p>
 | 
						|
 * @author Michael Koch (konqueror@gmx.de)
 | 
						|
 */
 | 
						|
public abstract class SetOfIntegerSyntax
 | 
						|
  implements Cloneable, Serializable
 | 
						|
{
 | 
						|
  private static final long serialVersionUID = 3666874174847632203L;
 | 
						|
 | 
						|
  private int[][] members;
 | 
						|
 | 
						|
  private static int[][] normalize(int[][] values, int size)
 | 
						|
  {
 | 
						|
    // Sort into increasing order.  First the first index is
 | 
						|
    // compared, then the second.
 | 
						|
    Arrays.sort(values, 0, size, new Comparator()
 | 
						|
                {
 | 
						|
                  public int compare(Object o1, Object o2)
 | 
						|
                  {
 | 
						|
                    int[] v1 = (int[]) o1;
 | 
						|
                    int[] v2 = (int[]) o2;
 | 
						|
                    if (v1[0] == v2[0])
 | 
						|
                      return v1[1] - v2[1];
 | 
						|
                    return v1[0] - v2[0];
 | 
						|
                  }
 | 
						|
                });
 | 
						|
 | 
						|
    // Now coalesce overlapping ranges.
 | 
						|
    int outIndex = 0;
 | 
						|
    for (int i = 0; i < size; ++i)
 | 
						|
      {
 | 
						|
        // Note that we compare with values[i][1]+1, since
 | 
						|
        // we can coalesce {0,1} with {2,x}.
 | 
						|
        int save = i;
 | 
						|
        while (i + 1 < size && values[i + 1][0] <= values[i][1] + 1)
 | 
						|
          {
 | 
						|
            values[i][1] = Math.max(values[i][1], values[i + 1][1]);
 | 
						|
            ++i;
 | 
						|
          }
 | 
						|
        values[outIndex++] = values[save];
 | 
						|
      }
 | 
						|
 | 
						|
    int[][] result = new int[outIndex][];
 | 
						|
    System.arraycopy(values, 0, result, 0, outIndex);
 | 
						|
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates a <code>SetOfIntegerSyntax</code> object.
 | 
						|
   *
 | 
						|
   * @param member the member value
 | 
						|
   *
 | 
						|
   * @exception IllegalArgumentException if member is < 0
 | 
						|
   */
 | 
						|
  protected SetOfIntegerSyntax(int member)
 | 
						|
  {
 | 
						|
    if (member < 0)
 | 
						|
      throw new IllegalArgumentException("member may not be less than 0");
 | 
						|
 | 
						|
    this.members = new int[][]{{member, member}};
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates a <code>SetOfIntegerSyntax</code> object.
 | 
						|
   *
 | 
						|
   * @param members the members to use in this set. If
 | 
						|
   * <code>null</code> an empty set is created.
 | 
						|
   *
 | 
						|
   * @exception IllegalArgumentException if any element is invalid
 | 
						|
   * @exception NullPointerException if any element of members is null
 | 
						|
   */
 | 
						|
  protected SetOfIntegerSyntax(int[][] members)
 | 
						|
  {
 | 
						|
    int[][] newMembers;
 | 
						|
    int outIndex = 0;
 | 
						|
    if (members == null)
 | 
						|
      newMembers = new int[0][];
 | 
						|
    else
 | 
						|
      {
 | 
						|
        newMembers = new int[members.length][];
 | 
						|
        for (int index = 0; index < members.length; index++)
 | 
						|
          {
 | 
						|
            int lower;
 | 
						|
            int upper;
 | 
						|
 | 
						|
            if (members[index].length == 1)
 | 
						|
              {
 | 
						|
                lower = members[index][0];
 | 
						|
                upper = members[index][0];
 | 
						|
              }
 | 
						|
            else if (members[index].length == 2)
 | 
						|
              {
 | 
						|
                lower = members[index][0];
 | 
						|
                upper = members[index][1];
 | 
						|
              }
 | 
						|
            else
 | 
						|
              throw new IllegalArgumentException("invalid member element");
 | 
						|
 | 
						|
            // We only want to reject non-null ranges where lower<0.
 | 
						|
            if (lower <= upper && lower < 0)
 | 
						|
              throw new IllegalArgumentException("invalid member element");
 | 
						|
 | 
						|
            if (lower <= upper)
 | 
						|
              {
 | 
						|
                int[] range = new int[2];
 | 
						|
                range[0] = lower;
 | 
						|
                range[1] = upper;
 | 
						|
                newMembers[outIndex++] = range;
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
    this.members = normalize(newMembers, outIndex);
 | 
						|
  }
 | 
						|
 | 
						|
  private boolean skipWhitespace(StringCharacterIterator i)
 | 
						|
  {
 | 
						|
    while (Character.isWhitespace(i.current()))
 | 
						|
      i.next();
 | 
						|
    return i.current() == CharacterIterator.DONE;
 | 
						|
  }
 | 
						|
 | 
						|
  private boolean skipNumber(StringCharacterIterator i)
 | 
						|
  {
 | 
						|
    boolean readAny = false;
 | 
						|
    while (Character.isDigit(i.current()))
 | 
						|
      {
 | 
						|
        readAny = true;
 | 
						|
        i.next();
 | 
						|
      }
 | 
						|
    return readAny;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates a <code>SetOfIntegerSyntax</code> object.
 | 
						|
   *
 | 
						|
   * @param s the members to use in this set in string form. If
 | 
						|
   * <code>null</code> an empty set is created.
 | 
						|
   *
 | 
						|
   * @exception IllegalArgumentException if any element is invalid
 | 
						|
   */
 | 
						|
  protected SetOfIntegerSyntax(String s)
 | 
						|
  {
 | 
						|
    if (s == null)
 | 
						|
      this.members = normalize(new int[0][], 0);
 | 
						|
    else
 | 
						|
      {
 | 
						|
        ArrayList vals = new ArrayList();
 | 
						|
 | 
						|
        StringCharacterIterator it = new StringCharacterIterator(s);
 | 
						|
 | 
						|
        while (true)
 | 
						|
          {
 | 
						|
            // Skip whitespace.
 | 
						|
            if (skipWhitespace(it))
 | 
						|
              break;
 | 
						|
 | 
						|
            // Parse integer.
 | 
						|
            int index = it.getIndex();
 | 
						|
            if (! skipNumber(it))
 | 
						|
              throw new IllegalArgumentException();
 | 
						|
            int[] item = new int[2];
 | 
						|
            item[0] = Integer.parseInt(s.substring(index, it.getIndex()));
 | 
						|
 | 
						|
            if (! skipWhitespace(it))
 | 
						|
              {
 | 
						|
                char c = it.current();
 | 
						|
                if (c == ':' || c == '-')
 | 
						|
                  {
 | 
						|
                  it.next();
 | 
						|
                  if (skipWhitespace(it))
 | 
						|
                    throw new IllegalArgumentException();
 | 
						|
                  index = it.getIndex();
 | 
						|
                  if (! skipNumber(it))
 | 
						|
                    throw new IllegalArgumentException();
 | 
						|
                  item[1] = Integer.parseInt(s.substring(index, it.getIndex()));
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  item[1] = item[0];
 | 
						|
              }
 | 
						|
            else
 | 
						|
              item[1] = item[0];
 | 
						|
 | 
						|
            if (item[0] <= item[1])
 | 
						|
              vals.add(item);
 | 
						|
 | 
						|
            if (skipWhitespace(it))
 | 
						|
              break;
 | 
						|
            if (it.current() != ',')
 | 
						|
              throw new IllegalArgumentException();
 | 
						|
            it.next();
 | 
						|
          }
 | 
						|
 | 
						|
        members = normalize((int[][]) vals.toArray(new int[0][]), vals.size());
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates a <code>SetOfIntegerSyntax</code> object.
 | 
						|
   *
 | 
						|
   * @param lowerBound the lower bound value
 | 
						|
   * @param upperBound the upper bound value
 | 
						|
   *
 | 
						|
   * @exception IllegalArgumentException if lowerBound <= upperbound
 | 
						|
   * and lowerBound < 0
 | 
						|
   */
 | 
						|
  protected SetOfIntegerSyntax(int lowerBound, int upperBound)
 | 
						|
  {
 | 
						|
    // We only want to reject non-null ranges where lower<0.
 | 
						|
    if (lowerBound <= upperBound
 | 
						|
        && lowerBound < 0)
 | 
						|
      throw new IllegalArgumentException();
 | 
						|
 | 
						|
    members = (lowerBound <= upperBound ? new int[][]{{lowerBound, upperBound}}
 | 
						|
                                        : new int[0][]);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Checks if this set contains the given value.
 | 
						|
   *
 | 
						|
   * @param value the value to test for
 | 
						|
   *
 | 
						|
   * @return true if this set contains value, false otherwise
 | 
						|
   */
 | 
						|
  public boolean contains(int value)
 | 
						|
  {
 | 
						|
    // This only works on a normalized member array.
 | 
						|
    for (int index = 0; index < members.length; index++)
 | 
						|
      {
 | 
						|
        if (value < members[index][0])
 | 
						|
          return false;
 | 
						|
        else if (value <= members[index][1])
 | 
						|
          return true;
 | 
						|
      }
 | 
						|
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Checks if this set contains the given value.
 | 
						|
   *
 | 
						|
   * @param value the value to test for
 | 
						|
   *
 | 
						|
   * @return true if this set contains value, false otherwise
 | 
						|
   */
 | 
						|
  public boolean contains(IntegerSyntax value)
 | 
						|
  {
 | 
						|
    return contains(value.getValue());
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Tests if the given object is equal to this object.
 | 
						|
   *
 | 
						|
   * @param obj the object to test
 | 
						|
   *
 | 
						|
   * @return true if both objects are equal, false otherwise.
 | 
						|
   */
 | 
						|
  public boolean equals(Object obj)
 | 
						|
  {
 | 
						|
    if (! (obj instanceof SetOfIntegerSyntax))
 | 
						|
      return false;
 | 
						|
    SetOfIntegerSyntax other = (SetOfIntegerSyntax) obj;
 | 
						|
    if (other.members.length != members.length)
 | 
						|
      return false;
 | 
						|
    for (int i = 0; i < members.length; ++i)
 | 
						|
      {
 | 
						|
        if (members[i][0] != other.members[i][0]
 | 
						|
            || members[i][1] != other.members[i][1])
 | 
						|
          return false;
 | 
						|
      }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns an array describing the members included in this set.
 | 
						|
   *
 | 
						|
   * @return The members in normalized array form.
 | 
						|
   */
 | 
						|
  public int[][] getMembers()
 | 
						|
  {
 | 
						|
    return (int[][]) members.clone();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the hashcode for this object.
 | 
						|
   *
 | 
						|
   * @return The hashcode.
 | 
						|
   */
 | 
						|
  public int hashCode()
 | 
						|
  {
 | 
						|
    int result = 0;
 | 
						|
    for (int i = 0; i < members.length; ++i)
 | 
						|
      result += members[i][0] + members[i][1];
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the smallest value that is greater than x which is in this set.
 | 
						|
   *
 | 
						|
   * @param x an integer value
 | 
						|
   *
 | 
						|
   * @return The next smallest integer value, or <code>-1</code> if there
 | 
						|
   * is no greater integer in the set.
 | 
						|
   */
 | 
						|
  public int next(int x)
 | 
						|
  {
 | 
						|
    for (int i = 0; i < members.length; ++i)
 | 
						|
      {
 | 
						|
        if (x >= members[i][1])
 | 
						|
          continue;
 | 
						|
        if (x < members[i][0])
 | 
						|
          return members[i][0];
 | 
						|
        // X is in this range.
 | 
						|
        return x + 1;
 | 
						|
      }
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the string representation for this object.
 | 
						|
   * The value is a zero length string for an empty set, or a comma seperated
 | 
						|
   * list of ranges and single values in the form <code>"1-2,5-7,10"</code>.
 | 
						|
   *
 | 
						|
   * @return The string representation.
 | 
						|
   */
 | 
						|
  public String toString()
 | 
						|
  {
 | 
						|
    StringBuilder sb = new StringBuilder();
 | 
						|
    for (int i = 0; i < members.length; ++i)
 | 
						|
      {
 | 
						|
        if (i > 0)
 | 
						|
          sb.append(',');
 | 
						|
        sb.append(members[i][0]);
 | 
						|
        if (members[i][0] != members[i][1])
 | 
						|
          {
 | 
						|
            sb.append('-');
 | 
						|
            sb.append(members[i][1]);
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return sb.toString();
 | 
						|
  }
 | 
						|
}
 |