001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package javax.print.attribute;
019:
020: import java.io.Serializable;
021: import java.util.Vector;
022:
023: public abstract class SetOfIntegerSyntax implements Cloneable,
024: Serializable {
025: private static final long serialVersionUID = 3666874174847632203L;
026:
027: private int[][] canonicalArray;
028:
029: protected SetOfIntegerSyntax(int value) {
030: if (value < 0) {
031: throw new IllegalArgumentException("Value " + value
032: + " is less than 0");
033: }
034: canonicalArray = new int[][] { { value, value } };
035: }
036:
037: protected SetOfIntegerSyntax(int lowerBound, int upperBound) {
038: if (lowerBound <= upperBound) {
039: if (lowerBound < 0) {
040: throw new IllegalArgumentException(
041: "Lower bound is less than 0");
042: }
043: canonicalArray = new int[][] { { lowerBound, upperBound } };
044: } else {
045: canonicalArray = new int[0][];
046: }
047: }
048:
049: protected SetOfIntegerSyntax(int[][] values) {
050: if (values == null) {
051: canonicalArray = new int[0][];
052: } else {
053: canonicalArray = rearrange(values);
054: }
055: }
056:
057: protected SetOfIntegerSyntax(String values) {
058: if (values == null) {
059: canonicalArray = new int[0][];
060: } else {
061: canonicalArray = parse(values);
062: }
063: }
064:
065: /**
066: * Parses given string containing set of integer and
067: * returns this set in canonical array form.
068: * One after another integer intervals are extracted from the string
069: * according comma-separated integer groups and than these intervals
070: * are organized in canonical array form.
071: */
072: private static int[][] parse(String values) {
073: int flag;
074: long num1long; /*first number in a range*/
075: long num2long; /*second number in a range*/
076: char symbol;
077: /*vector for storing integer intervals in canonical form*/
078: Vector<int[]> vector = new Vector<int[]>();
079: /*obtain an array of intervals from the string*/
080: String[] str = values.split(",");
081: int n = str.length;
082: /*take next interval*/
083: for (int i = 0; i < n; i++) {
084: flag = 0;
085: num1long = 0;
086: num2long = 0;
087: /*take next literal in interval*/
088: for (int j = 0; j < str[i].length(); j++) {
089: symbol = str[i].charAt(j);
090: switch (flag) {
091: /*before the first number*/
092: case 0:
093: if (Character.isWhitespace(symbol)) {
094: continue;
095: } else if (Character.isDigit(symbol)) {
096: num1long = Character.digit(symbol, 10);
097: num2long = num1long;
098: flag = 1;
099: } else {
100: throw new IllegalArgumentException();
101: }
102: break;
103: /*before the separator*/
104: case 1:
105: if (Character.isWhitespace(symbol)) {
106: continue;
107: } else if (Character.isDigit(symbol)) {
108: num1long = num1long * 10
109: + Character.digit(symbol, 10);
110: if (num1long > Integer.MAX_VALUE) {
111: throw new IllegalArgumentException(num1long
112: + " is out of int range");
113: }
114: num2long = num1long;
115: } else if ((symbol == ':') || (symbol == '-')) {
116: flag = 2;
117: } else {
118: throw new IllegalArgumentException();
119: }
120: break;
121: /*before the second number*/
122: case 2:
123: if (Character.isWhitespace(symbol)) {
124: continue;
125: } else if (Character.isDigit(symbol)) {
126: num2long = Character.digit(symbol, 10);
127: flag = 3;
128: } else {
129: throw new IllegalArgumentException();
130: }
131: break;
132: /*afrer the first digit of second number*/
133: case 3:
134: if (Character.isWhitespace(symbol)) {
135: continue;
136: } else if (Character.isDigit(symbol)) {
137: num2long = num2long * 10
138: + Character.digit(symbol, 10);
139: if (num2long > Integer.MAX_VALUE) {
140: throw new IllegalArgumentException(num2long
141: + " is out of int range");
142: }
143: } else {
144: throw new IllegalArgumentException();
145: }
146: break;
147: }
148: }
149: /*Add the int interval to the vector if the interval in the
150: string form had legal syntax*/
151: if (((flag == 1) || (flag == 3)) && (num1long <= num2long)) {
152: addRange(vector, (int) num1long, (int) num2long);
153: }
154: }
155: return vector.toArray(new int[vector.size()][]);
156: }
157:
158: /*
159: * Work this array out to cannonical array form.
160: */
161: private static int[][] rearrange(int[][] values) {
162: Vector<int[]> vector = new Vector<int[]>();
163: int num1;
164: int num2;
165: for (int[] element : values) {
166: if (element == null) {
167: throw new NullPointerException(
168: "int[][] array has null element");
169: }
170: if (element.length == 1) {
171: num1 = element[0];
172: num2 = element[0];
173: } else if (element.length == 2) {
174: num1 = element[0];
175: num2 = element[1];
176: } else {
177: throw new IllegalArgumentException(
178: "Only array of length-1 "
179: + "or length-2 arrays of ints are valid");
180: }
181: if (num1 < 0) {
182: throw new IllegalArgumentException("Valid values are "
183: + "not less than 0");
184: } else if (num1 <= num2) {
185: addRange(vector, num1, num2);
186: }
187: }
188: return vector.toArray(new int[vector.size()][]);
189: }
190:
191: /*
192: * Adds interval [lowerBound, upperBound] to the vector containing
193: * intervals in cannoical form and modifies it so that cannonical form
194: * is saved.
195: */
196: private static void addRange(Vector<int[]> vector, int lowerBound,
197: int upperBound) {
198: int l1; /*lowerBound of the first interval*/
199: int u1; /*upperBound of the first interval*/
200: int l2; /*lowerBound of the next interval*/
201: int u2; /*upperBound of the next interval*/
202: /*add interval [lowerBound, upperBound] to the vector*/
203: vector.add(new int[] { lowerBound, upperBound });
204: /*enumerate all intervals in the vector*/
205: for (int i = vector.size() - 2; i >= 0; i--) {
206: l1 = vector.elementAt(i)[0];
207: u1 = vector.elementAt(i)[1];
208: l2 = vector.elementAt(i + 1)[0];
209: u2 = vector.elementAt(i + 1)[1];
210: /*check if two consecutive intervals overlap*/
211: if (Math.max(l1, l2) - Math.min(u1, u2) <= 1) {
212: /*make new interval from two consecutive intervals
213: contained all theirs elements*/
214: vector.setElementAt(new int[] { Math.min(l1, l2),
215: Math.max(u1, u2) }, i);
216: vector.removeElementAt(i + 1);
217: /*if two consecutive intervals doesn't overlap but
218: lowerBound of the first interval is bigger than
219: upperBound of the next interval
220: than interchange theirs position*/
221: } else if (l1 > u2) {
222: vector.setElementAt(new int[] { l2, u2 }, i);
223: vector.setElementAt(new int[] { l1, u1 }, i + 1);
224: } else {
225: break;
226: }
227: }
228: }
229:
230: public boolean contains(int value) {
231: for (int[] element : canonicalArray) {
232: if ((value >= element[0]) && (value <= element[1])) {
233: return true;
234: }
235: }
236: return false;
237: }
238:
239: public boolean contains(IntegerSyntax attribute) {
240: return contains(attribute.getValue());
241: }
242:
243: @Override
244: public boolean equals(Object object) {
245: if (object instanceof SetOfIntegerSyntax) {
246: int[][] compare = ((SetOfIntegerSyntax) object).canonicalArray;
247: int n = compare.length;
248: if (n == canonicalArray.length) {
249: for (int i = 0; i < n; i++) {
250: if ((canonicalArray[i][0] != compare[i][0])
251: || (canonicalArray[i][1] != compare[i][1])) {
252: return false;
253: }
254: }
255: return true;
256: }
257: return false;
258: }
259: return false;
260: }
261:
262: public int[][] getMembers() {
263: int n = canonicalArray.length;
264: int[][] members = new int[n][];
265: for (int i = 0; i < n; i++) {
266: members[i] = new int[] { canonicalArray[i][0],
267: canonicalArray[i][1] };
268: }
269: return members;
270: }
271:
272: @Override
273: public int hashCode() {
274: int hashCode = 0;
275: for (int[] element : canonicalArray) {
276: hashCode += element[0] + element[1];
277: }
278: return hashCode;
279: }
280:
281: public int next(int value) {
282: for (int[] element : canonicalArray) {
283: if (value < element[0]) {
284: return element[0];
285: } else if (value < element[1]) {
286: return value + 1;
287: }
288: }
289: return -1;
290: }
291:
292: @Override
293: public String toString() {
294: StringBuffer stringSet = new StringBuffer("");
295: for (int i = 0; i < canonicalArray.length; i++) {
296: if (i > 0) {
297: stringSet.append(",");
298: }
299: stringSet.append(canonicalArray[i][0]);
300: if (canonicalArray[i][0] != canonicalArray[i][1]) {
301: stringSet.append("-");
302: stringSet.append(canonicalArray[i][1]);
303: }
304: }
305: return stringSet.toString();
306: }
307: }
|