Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/javax/print/attribute/SetOfIntegerSyntax.java
41159 views
1
/*
2
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package javax.print.attribute;
27
28
import java.io.Serial;
29
import java.io.Serializable;
30
import java.util.Vector;
31
32
/**
33
* Class {@code SetOfIntegerSyntax} is an abstract base class providing the
34
* common implementation of all attributes whose value is a set of nonnegative
35
* integers. This includes attributes whose value is a single range of integers
36
* and attributes whose value is a set of ranges of integers.
37
* <p>
38
* You can construct an instance of {@code SetOfIntegerSyntax} by giving it in
39
* "string form." The string consists of zero or more comma-separated integer
40
* groups. Each integer group consists of either one integer, two integers
41
* separated by a hyphen ({@code -}), or two integers separated by a colon
42
* ({@code :}). Each integer consists of one or more decimal digits ({@code 0}
43
* through {@code 9}). Whitespace characters cannot appear within an integer but
44
* are otherwise ignored. For example: {@code ""}, {@code "1"}, {@code "5-10"},
45
* {@code "1:2, 4"}.
46
* <p>
47
* You can also construct an instance of {@code SetOfIntegerSyntax} by giving it
48
* in "array form." Array form consists of an array of zero or more integer
49
* groups where each integer group is a length-1 or length-2 array of
50
* {@code int}s; for example, {@code int[0][]}, {@code int[][]{{1}}},
51
* {@code int[][]{{5,10}}}, {@code int[][]{{1,2},{4}}}.
52
* <p>
53
* In both string form and array form, each successive integer group gives a
54
* range of integers to be included in the set. The first integer in each group
55
* gives the lower bound of the range; the second integer in each group gives
56
* the upper bound of the range; if there is only one integer in the group, the
57
* upper bound is the same as the lower bound. If the upper bound is less than
58
* the lower bound, it denotes a {@code null} range (no values). If the upper
59
* bound is equal to the lower bound, it denotes a range consisting of a single
60
* value. If the upper bound is greater than the lower bound, it denotes a range
61
* consisting of more than one value. The ranges may appear in any order and are
62
* allowed to overlap. The union of all the ranges gives the set's contents.
63
* Once a {@code SetOfIntegerSyntax} instance is constructed, its value is
64
* immutable.
65
* <p>
66
* The {@code SetOfIntegerSyntax} object's value is actually stored in
67
* "<i>canonical</i> array form." This is the same as array form, except there
68
* are no {@code null} ranges; the members of the set are represented in as few
69
* ranges as possible (i.e., overlapping ranges are coalesced); the ranges
70
* appear in ascending order; and each range is always represented as a
71
* length-two array of {@code int}s in the form {lower bound, upper bound}. An
72
* empty set is represented as a zero-length array.
73
* <p>
74
* Class {@code SetOfIntegerSyntax} has operations to return the set's members
75
* in canonical array form, to test whether a given integer is a member of the
76
* set, and to iterate through the members of the set.
77
*
78
* @author David Mendenhall
79
* @author Alan Kaminsky
80
*/
81
public abstract class SetOfIntegerSyntax implements Serializable, Cloneable {
82
83
/**
84
* Use serialVersionUID from JDK 1.4 for interoperability.
85
*/
86
@Serial
87
private static final long serialVersionUID = 3666874174847632203L;
88
89
/**
90
* This set's members in canonical array form.
91
*
92
* @serial
93
*/
94
private int[][] members;
95
96
/**
97
* Construct a new set-of-integer attribute with the given members in string
98
* form.
99
*
100
* @param members set members in string form. If {@code null}, an empty set
101
* is constructed.
102
* @throws IllegalArgumentException if {@code members} does not obey the
103
* proper syntax
104
*/
105
protected SetOfIntegerSyntax(String members) {
106
this.members = parse (members);
107
}
108
109
/**
110
* Parse the given string, returning canonical array form.
111
*
112
* @param members the string
113
* @return the canonical array form
114
*/
115
private static int[][] parse(String members) {
116
// Create vector to hold int[] elements, each element being one range
117
// parsed out of members.
118
Vector<int[]> theRanges = new Vector<>();
119
120
// Run state machine over members.
121
int n = (members == null ? 0 : members.length());
122
int i = 0;
123
int state = 0;
124
int lb = 0;
125
int ub = 0;
126
char c;
127
int digit;
128
while (i < n) {
129
c = members.charAt(i ++);
130
switch (state) {
131
132
case 0: // Before first integer in first group
133
if (Character.isWhitespace(c)) {
134
state = 0;
135
}
136
else if ((digit = Character.digit(c, 10)) != -1) {
137
lb = digit;
138
state = 1;
139
} else {
140
throw new IllegalArgumentException();
141
}
142
break;
143
144
case 1: // In first integer in a group
145
if (Character.isWhitespace(c)){
146
state = 2;
147
} else if ((digit = Character.digit(c, 10)) != -1) {
148
lb = 10 * lb + digit;
149
state = 1;
150
} else if (c == '-' || c == ':') {
151
state = 3;
152
} else if (c == ',') {
153
accumulate (theRanges, lb, lb);
154
state = 6;
155
} else {
156
throw new IllegalArgumentException();
157
}
158
break;
159
160
case 2: // After first integer in a group
161
if (Character.isWhitespace(c)) {
162
state = 2;
163
}
164
else if (c == '-' || c == ':') {
165
state = 3;
166
}
167
else if (c == ',') {
168
accumulate(theRanges, lb, lb);
169
state = 6;
170
} else {
171
throw new IllegalArgumentException();
172
}
173
break;
174
175
case 3: // Before second integer in a group
176
if (Character.isWhitespace(c)) {
177
state = 3;
178
} else if ((digit = Character.digit(c, 10)) != -1) {
179
ub = digit;
180
state = 4;
181
} else {
182
throw new IllegalArgumentException();
183
}
184
break;
185
186
case 4: // In second integer in a group
187
if (Character.isWhitespace(c)) {
188
state = 5;
189
} else if ((digit = Character.digit(c, 10)) != -1) {
190
ub = 10 * ub + digit;
191
state = 4;
192
} else if (c == ',') {
193
accumulate(theRanges, lb, ub);
194
state = 6;
195
} else {
196
throw new IllegalArgumentException();
197
}
198
break;
199
200
case 5: // After second integer in a group
201
if (Character.isWhitespace(c)) {
202
state = 5;
203
} else if (c == ',') {
204
accumulate(theRanges, lb, ub);
205
state = 6;
206
} else {
207
throw new IllegalArgumentException();
208
}
209
break;
210
211
case 6: // Before first integer in second or later group
212
if (Character.isWhitespace(c)) {
213
state = 6;
214
} else if ((digit = Character.digit(c, 10)) != -1) {
215
lb = digit;
216
state = 1;
217
} else {
218
throw new IllegalArgumentException();
219
}
220
break;
221
}
222
}
223
224
// Finish off the state machine.
225
switch (state) {
226
case 0: // Before first integer in first group
227
break;
228
case 1: // In first integer in a group
229
case 2: // After first integer in a group
230
accumulate(theRanges, lb, lb);
231
break;
232
case 4: // In second integer in a group
233
case 5: // After second integer in a group
234
accumulate(theRanges, lb, ub);
235
break;
236
case 3: // Before second integer in a group
237
case 6: // Before first integer in second or later group
238
throw new IllegalArgumentException();
239
}
240
241
// Return canonical array form.
242
return canonicalArrayForm (theRanges);
243
}
244
245
/**
246
* Accumulate the given range (lb .. ub) into the canonical array form into
247
* the given vector of int[] objects.
248
*/
249
private static void accumulate(Vector<int[]> ranges, int lb,int ub) {
250
// Make sure range is non-null.
251
if (lb <= ub) {
252
// Stick range at the back of the vector.
253
ranges.add(new int[] {lb, ub});
254
255
// Work towards the front of the vector to integrate the new range
256
// with the existing ranges.
257
for (int j = ranges.size()-2; j >= 0; -- j) {
258
// Get lower and upper bounds of the two ranges being compared.
259
int[] rangea = ranges.elementAt (j);
260
int lba = rangea[0];
261
int uba = rangea[1];
262
int[] rangeb = ranges.elementAt (j+1);
263
int lbb = rangeb[0];
264
int ubb = rangeb[1];
265
/*
266
* If the two ranges overlap or are adjacent, coalesce them. The
267
* two ranges overlap if the larger lower bound is less than or
268
* equal to the smaller upper bound. The two ranges are adjacent
269
* if the larger lower bound is one greater than the smaller
270
* upper bound.
271
*/
272
if (Math.max(lba, lbb) - Math.min(uba, ubb) <= 1) {
273
// The coalesced range is from the smaller lower bound to
274
// the larger upper bound.
275
ranges.setElementAt(new int[]
276
{Math.min(lba, lbb),
277
Math.max(uba, ubb)}, j);
278
ranges.remove (j+1);
279
} else if (lba > lbb) {
280
281
/* If the two ranges don't overlap and aren't adjacent but
282
* are out of order, swap them.
283
*/
284
ranges.setElementAt (rangeb, j);
285
ranges.setElementAt (rangea, j+1);
286
} else {
287
/*
288
* If the two ranges don't overlap and aren't adjacent and
289
* aren't out of order, we're done early.
290
*/
291
break;
292
}
293
}
294
}
295
}
296
297
/**
298
* Convert the given vector of int[] objects to canonical array form.
299
*/
300
private static int[][] canonicalArrayForm(Vector<int[]> ranges) {
301
return ranges.toArray (new int[ranges.size()][]);
302
}
303
304
/**
305
* Construct a new set-of-integer attribute with the given members in array
306
* form.
307
*
308
* @param members set members in array form. If {@code null}, an empty set
309
* is constructed.
310
* @throws NullPointerException if any element of {@code members} is
311
* {@code null}
312
* @throws IllegalArgumentException if any element of {@code members} is not
313
* a length-one or length-two array or if any {@code non-null} range
314
* in {@code members} has a lower bound less than zero
315
*/
316
protected SetOfIntegerSyntax(int[][] members) {
317
this.members = parse (members);
318
}
319
320
/**
321
* Parse the given array form, returning canonical array form.
322
*/
323
private static int[][] parse(int[][] members) {
324
// Create vector to hold int[] elements, each element being one range
325
// parsed out of members.
326
Vector<int[]> ranges = new Vector<>();
327
328
// Process all integer groups in members.
329
int n = (members == null ? 0 : members.length);
330
for (int i = 0; i < n; ++ i) {
331
// Get lower and upper bounds of the range.
332
int lb, ub;
333
if (members[i].length == 1) {
334
lb = ub = members[i][0];
335
} else if (members[i].length == 2) {
336
lb = members[i][0];
337
ub = members[i][1];
338
} else {
339
throw new IllegalArgumentException();
340
}
341
342
// Verify valid bounds.
343
if (lb <= ub && lb < 0) {
344
throw new IllegalArgumentException();
345
}
346
347
// Accumulate the range.
348
accumulate(ranges, lb, ub);
349
}
350
351
// Return canonical array form.
352
return canonicalArrayForm (ranges);
353
}
354
355
/**
356
* Construct a new set-of-integer attribute containing a single integer.
357
*
358
* @param member set member
359
* @throws IllegalArgumentException if {@code member} is negative
360
*/
361
protected SetOfIntegerSyntax(int member) {
362
if (member < 0) {
363
throw new IllegalArgumentException();
364
}
365
members = new int[][] {{member, member}};
366
}
367
368
/**
369
* Construct a new set-of-integer attribute containing a single range of
370
* integers. If the lower bound is greater than the upper bound (a null
371
* range), an empty set is constructed.
372
*
373
* @param lowerBound Lower bound of the range
374
* @param upperBound Upper bound of the range
375
* @throws IllegalArgumentException if the range is {@code non-null} and
376
* {@code lowerBound} is less than zero
377
*/
378
protected SetOfIntegerSyntax(int lowerBound, int upperBound) {
379
if (lowerBound <= upperBound && lowerBound < 0) {
380
throw new IllegalArgumentException();
381
}
382
members = lowerBound <=upperBound ?
383
new int[][] {{lowerBound, upperBound}} :
384
new int[0][];
385
}
386
387
/**
388
* Obtain this set-of-integer attribute's members in canonical array form.
389
* The returned array is "safe;" the client may alter it without affecting
390
* this set-of-integer attribute.
391
*
392
* @return this set-of-integer attribute's members in canonical array form
393
*/
394
public int[][] getMembers() {
395
int n = members.length;
396
int[][] result = new int[n][];
397
for (int i = 0; i < n; ++ i) {
398
result[i] = new int[] {members[i][0], members[i][1]};
399
}
400
return result;
401
}
402
403
/**
404
* Determine if this set-of-integer attribute contains the given value.
405
*
406
* @param x the Integer value
407
* @return {@code true} if this set-of-integer attribute contains the value
408
* {@code x}, {@code false} otherwise
409
*/
410
public boolean contains(int x) {
411
// Do a linear search to find the range that contains x, if any.
412
int n = members.length;
413
for (int i = 0; i < n; ++ i) {
414
if (x < members[i][0]) {
415
return false;
416
} else if (x <= members[i][1]) {
417
return true;
418
}
419
}
420
return false;
421
}
422
423
/**
424
* Determine if this set-of-integer attribute contains the given integer
425
* attribute's value.
426
*
427
* @param attribute the Integer attribute
428
* @return {@code true} if this set-of-integer attribute contains
429
* {@code attribute}'s value, {@code false} otherwise
430
*/
431
public boolean contains(IntegerSyntax attribute) {
432
return contains (attribute.getValue());
433
}
434
435
/**
436
* Determine the smallest integer in this set-of-integer attribute that is
437
* greater than the given value. If there are no integers in this
438
* set-of-integer attribute greater than the given value, {@code -1} is
439
* returned. (Since a set-of-integer attribute can only contain nonnegative
440
* values, {@code -1} will never appear in the set.) You can use the
441
* {@code next()} method to iterate through the integer values in a
442
* set-of-integer attribute in ascending order, like this:
443
* <pre>
444
* SetOfIntegerSyntax attribute = . . .;
445
* int i = -1;
446
* while ((i = attribute.next (i)) != -1)
447
* {
448
* foo (i);
449
* }
450
* </pre>
451
*
452
* @param x the Integer value
453
* @return the smallest integer in this set-of-integer attribute that is
454
* greater than {@code x}, or {@code -1} if no integer in this
455
* set-of-integer attribute is greater than {@code x}.
456
*/
457
public int next(int x) {
458
// Do a linear search to find the range that contains x, if any.
459
int n = members.length;
460
for (int i = 0; i < n; ++ i) {
461
if (x < members[i][0]) {
462
return members[i][0];
463
} else if (x < members[i][1]) {
464
return x + 1;
465
}
466
}
467
return -1;
468
}
469
470
/**
471
* Returns whether this set-of-integer attribute is equivalent to the passed
472
* in object. To be equivalent, all of the following conditions must be
473
* true:
474
* <ol type=1>
475
* <li>{@code object} is not {@code null}.
476
* <li>{@code object} is an instance of class {@code SetOfIntegerSyntax}.
477
* <li>This set-of-integer attribute's members and {@code object}'s
478
* members are the same.
479
* </ol>
480
*
481
* @param object {@code Object} to compare to
482
* @return {@code true} if {@code object} is equivalent to this
483
* set-of-integer attribute, {@code false} otherwise
484
*/
485
public boolean equals(Object object) {
486
if (object != null && object instanceof SetOfIntegerSyntax) {
487
int[][] myMembers = this.members;
488
int[][] otherMembers = ((SetOfIntegerSyntax) object).members;
489
int m = myMembers.length;
490
int n = otherMembers.length;
491
if (m == n) {
492
for (int i = 0; i < m; ++ i) {
493
if (myMembers[i][0] != otherMembers[i][0] ||
494
myMembers[i][1] != otherMembers[i][1]) {
495
return false;
496
}
497
}
498
return true;
499
} else {
500
return false;
501
}
502
} else {
503
return false;
504
}
505
}
506
507
/**
508
* Returns a hash code value for this set-of-integer attribute. The hash
509
* code is the sum of the lower and upper bounds of the ranges in the
510
* canonical array form, or 0 for an empty set.
511
*/
512
public int hashCode() {
513
int result = 0;
514
int n = members.length;
515
for (int i = 0; i < n; ++ i) {
516
result += members[i][0] + members[i][1];
517
}
518
return result;
519
}
520
521
/**
522
* Returns a string value corresponding to this set-of-integer attribute.
523
* The string value is a zero-length string if this set is empty. Otherwise,
524
* the string value is a comma-separated list of the ranges in the canonical
525
* array form, where each range is represented as <code>"<i>i</i>"</code> if
526
* the lower bound equals the upper bound or
527
* <code>"<i>i</i>-<i>j</i>"</code> otherwise.
528
*/
529
public String toString() {
530
StringBuilder result = new StringBuilder();
531
int n = members.length;
532
for (int i = 0; i < n; i++) {
533
if (i > 0) {
534
result.append (',');
535
}
536
result.append (members[i][0]);
537
if (members[i][0] != members[i][1]) {
538
result.append ('-');
539
result.append (members[i][1]);
540
}
541
}
542
return result.toString();
543
}
544
}
545
546