1 /* SetOfIntegerSyntax.java --
2 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package javax
.print
.attribute
;
40 import java
.io
.Serializable
;
41 import java
.text
.CharacterIterator
;
42 import java
.text
.StringCharacterIterator
;
43 import java
.util
.ArrayList
;
44 import java
.util
.Arrays
;
45 import java
.util
.Comparator
;
48 * <code>SetOfIntegerSyntax</code> is the abstract base class of all attribute
49 * classes which provide a set of non-negative integers as value (e.g. the
50 * page ranges to print) represented as single values or ranges of values.
52 * A <code>SetOfIntegerSyntax</code> instance consists of an integer array of
53 * ranges. Ranges may have the same lower and upper bound representing a single
54 * integer value. Ranges with a lower bound greater than the upper bound are
55 * null ranges and discarded. Ranges may overlap in their values. In no case
56 * negative integers are allowed.
59 * There are several constructors available:
61 * <li><code>SetOfIntegerSyntax(int member)</code><br>
62 * Constructor for an instance with only one integer value.
64 * <li><code>SetOfIntegerSyntax(int lowerBound, int upperBound)</code><br>
65 * Constructor for an instance with one range of integer values.
67 * <li><code>SetOfIntegerSyntax(int[][] members)</code><br>
68 * Flexible constructor for an instance with several single integer values
69 * and/or several ranges of integer values. The allowed array form is an
70 * array of integer arrays of length one or two. Examples are:
71 * <code>int[0][]</code> for empty set of integers, <code>int[][] {{1}}</code>
72 * , <code>int[][] {{1,5}}</code>, <code>int[][] {{1,5},{7,9}}</code>,
73 * <code>int[][] {{3,7},{19}}</code>.
75 * <li><code>SetOfIntegerSyntax(String s)</code><br>
76 * Flexible constructor for an instance with several single integer values
77 * and/or several ranges of integer values. The allowed String instance have
78 * to be a String with comma separated ranges of integer values or single
79 * values. Ranges are represented by two integer with a hypen (-) or colon (:)
80 * between the lower and upper bound value. Whitespace characters are ignored.
81 * Examples are: <code>""</code> for an empty set of integers,
82 * <code>"1"</code>, <code>"1-5"</code>, <code>"1-5,7-9"</code>,
83 * <code>"3-7,19"</code> and <code>"1:2,4"</code>.
88 * <b>Internal storage:</b><br>
89 * The set of integers are stored internally in a normalized array form.
90 * In the normalized array form the set of integer ranges are represented
91 * in as few ranges as possible and overlapping ranges are merged. The ranges
92 * are always represented as an integer array of length two with ranges
93 * stored in {lower bound, upper bound} form. The ranges are stored in
94 * ascending order, without any null ranges.
96 * @author Michael Koch (konqueror@gmx.de)
98 public abstract class SetOfIntegerSyntax
99 implements Cloneable
, Serializable
101 private static final long serialVersionUID
= 3666874174847632203L;
103 private int[][] members
;
105 private static int[][] normalize(int[][] values
, int size
)
107 // Sort into increasing order. First the first index is
108 // compared, then the second.
109 Arrays
.sort(values
, 0, size
, new Comparator()
111 public int compare(Object o1
, Object o2
)
113 int[] v1
= (int[]) o1
;
114 int[] v2
= (int[]) o2
;
116 return v1
[1] - v2
[1];
117 return v1
[0] - v2
[0];
121 // Now coalesce overlapping ranges.
123 for (int i
= 0; i
< size
; ++i
)
125 // Note that we compare with values[i][1]+1, since
126 // we can coalesce {0,1} with {2,x}.
128 while (i
+ 1 < size
&& values
[i
+ 1][0] <= values
[i
][1] + 1)
130 values
[i
][1] = Math
.max(values
[i
][1], values
[i
+ 1][1]);
133 values
[outIndex
++] = values
[save
];
136 int[][] result
= new int[outIndex
][];
137 System
.arraycopy(values
, 0, result
, 0, outIndex
);
143 * Creates a <code>SetOfIntegerSyntax</code> object.
145 * @param member the member value
147 * @exception IllegalArgumentException if member is < 0
149 protected SetOfIntegerSyntax(int member
)
152 throw new IllegalArgumentException("member may not be less than 0");
154 this.members
= new int[][]{{member
, member
}};
158 * Creates a <code>SetOfIntegerSyntax</code> object.
160 * @param members the members to use in this set. If
161 * <code>null</code> an empty set is created.
163 * @exception IllegalArgumentException if any element is invalid
164 * @exception NullPointerException if any element of members is null
166 protected SetOfIntegerSyntax(int[][] members
)
171 newMembers
= new int[0][];
174 newMembers
= new int[members
.length
][];
175 for (int index
= 0; index
< members
.length
; index
++)
180 if (members
[index
].length
== 1)
182 lower
= members
[index
][0];
183 upper
= members
[index
][0];
185 else if (members
[index
].length
== 2)
187 lower
= members
[index
][0];
188 upper
= members
[index
][1];
191 throw new IllegalArgumentException("invalid member element");
193 // We only want to reject non-null ranges where lower<0.
194 if (lower
<= upper
&& lower
< 0)
195 throw new IllegalArgumentException("invalid member element");
199 int[] range
= new int[2];
202 newMembers
[outIndex
++] = range
;
207 this.members
= normalize(newMembers
, outIndex
);
210 private boolean skipWhitespace(StringCharacterIterator i
)
212 while (Character
.isWhitespace(i
.current()))
214 return i
.current() == CharacterIterator
.DONE
;
217 private boolean skipNumber(StringCharacterIterator i
)
219 boolean readAny
= false;
220 while (Character
.isDigit(i
.current()))
229 * Creates a <code>SetOfIntegerSyntax</code> object.
231 * @param s the members to use in this set in string form. If
232 * <code>null</code> an empty set is created.
234 * @exception IllegalArgumentException if any element is invalid
236 protected SetOfIntegerSyntax(String s
)
239 this.members
= normalize(new int[0][], 0);
242 ArrayList vals
= new ArrayList();
244 StringCharacterIterator it
= new StringCharacterIterator(s
);
249 if (skipWhitespace(it
))
253 int index
= it
.getIndex();
254 if (! skipNumber(it
))
255 throw new IllegalArgumentException();
256 int[] item
= new int[2];
257 item
[0] = Integer
.parseInt(s
.substring(index
, it
.getIndex()));
259 if (! skipWhitespace(it
))
261 char c
= it
.current();
262 if (c
== ':' || c
== '-')
265 if (skipWhitespace(it
))
266 throw new IllegalArgumentException();
267 index
= it
.getIndex();
268 if (! skipNumber(it
))
269 throw new IllegalArgumentException();
270 item
[1] = Integer
.parseInt(s
.substring(index
, it
.getIndex()));
278 if (item
[0] <= item
[1])
281 if (skipWhitespace(it
))
283 if (it
.current() != ',')
284 throw new IllegalArgumentException();
288 members
= normalize((int[][]) vals
.toArray(new int[0][]), vals
.size());
293 * Creates a <code>SetOfIntegerSyntax</code> object.
295 * @param lowerBound the lower bound value
296 * @param upperBound the upper bound value
298 * @exception IllegalArgumentException if lowerBound <= upperbound
299 * and lowerBound < 0
301 protected SetOfIntegerSyntax(int lowerBound
, int upperBound
)
303 // We only want to reject non-null ranges where lower<0.
304 if (lowerBound
<= upperBound
306 throw new IllegalArgumentException();
308 members
= (lowerBound
<= upperBound ?
new int[][]{{lowerBound
, upperBound
}}
313 * Checks if this set contains the given value.
315 * @param value the value to test for
317 * @return true if this set contains value, false otherwise
319 public boolean contains(int value
)
321 // This only works on a normalized member array.
322 for (int index
= 0; index
< members
.length
; index
++)
324 if (value
< members
[index
][0])
326 else if (value
<= members
[index
][1])
334 * Checks if this set contains the given value.
336 * @param value the value to test for
338 * @return true if this set contains value, false otherwise
340 public boolean contains(IntegerSyntax value
)
342 return contains(value
.getValue());
346 * Tests if the given object is equal to this object.
348 * @param obj the object to test
350 * @return true if both objects are equal, false otherwise.
352 public boolean equals(Object obj
)
354 if (! (obj
instanceof SetOfIntegerSyntax
))
356 SetOfIntegerSyntax other
= (SetOfIntegerSyntax
) obj
;
357 if (other
.members
.length
!= members
.length
)
359 for (int i
= 0; i
< members
.length
; ++i
)
361 if (members
[i
][0] != other
.members
[i
][0]
362 || members
[i
][1] != other
.members
[i
][1])
369 * Returns an array describing the members included in this set.
371 * @return The members in normalized array form.
373 public int[][] getMembers()
375 return (int[][]) members
.clone();
379 * Returns the hashcode for this object.
381 * @return The hashcode.
383 public int hashCode()
386 for (int i
= 0; i
< members
.length
; ++i
)
387 result
+= members
[i
][0] + members
[i
][1];
392 * Returns the smallest value that is greater than x which is in this set.
394 * @param x an integer value
396 * @return The next smallest integer value, or <code>-1</code> if there
397 * is no greater integer in the set.
399 public int next(int x
)
401 for (int i
= 0; i
< members
.length
; ++i
)
403 if (x
>= members
[i
][1])
405 if (x
< members
[i
][0])
406 return members
[i
][0];
407 // X is in this range.
414 * Returns the string representation for this object.
415 * The value is a zero length string for an empty set, or a comma seperated
416 * list of ranges and single values in the form <code>"1-2,5-7,10"</code>.
418 * @return The string representation.
420 public String
toString()
422 StringBuilder sb
= new StringBuilder();
423 for (int i
= 0; i
< members
.length
; ++i
)
427 sb
.append(members
[i
][0]);
428 if (members
[i
][0] != members
[i
][1])
431 sb
.append(members
[i
][1]);
434 return sb
.toString();