Line 0
Link Here
|
|
|
1 |
/* |
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
3 |
* |
4 |
* Copyright 2010 Sun Microsystems, Inc. All rights reserved. |
5 |
* |
6 |
* The contents of this file are subject to the terms of either the GNU |
7 |
* General Public License Version 2 only ("GPL") or the Common |
8 |
* Development and Distribution License("CDDL") (collectively, the |
9 |
* "License"). You may not use this file except in compliance with the |
10 |
* License. You can obtain a copy of the License at |
11 |
* http://www.netbeans.org/cddl-gplv2.html |
12 |
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the |
13 |
* specific language governing permissions and limitations under the |
14 |
* License. When distributing the software, include this License Header |
15 |
* Notice in each file and include the License file at |
16 |
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this |
17 |
* particular file as subject to the "Classpath" exception as provided |
18 |
* by Sun in the GPL Version 2 section of the License file that |
19 |
* accompanied this code. If applicable, add the following below the |
20 |
* License Header, with the fields enclosed by brackets [] replaced by |
21 |
* your own identifying information: |
22 |
* "Portions Copyrighted [year] [name of copyright owner]" |
23 |
* |
24 |
* If you wish your version of this file to be governed by only the CDDL |
25 |
* or only the GPL Version 2, indicate your decision by adding |
26 |
* "[Contributor] elects to include this software in this distribution |
27 |
* under the [CDDL or GPL Version 2] license." If you do not indicate a |
28 |
* single choice of license, a recipient has the option to distribute |
29 |
* your version of this file under either the CDDL, the GPL Version 2 or |
30 |
* to extend the choice of license to its licensees as provided above. |
31 |
* However, if you add GPL Version 2 code and therefore, elected the GPL |
32 |
* Version 2 license, then the option applies only if the new code is |
33 |
* made subject to such option by the copyright holder. |
34 |
* |
35 |
* Contributor(s): |
36 |
* |
37 |
* Portions Copyrighted 2010 Sun Microsystems, Inc. |
38 |
*/ |
39 |
package org.openide.util; |
40 |
|
41 |
import java.util.Arrays; |
42 |
import java.util.Comparator; |
43 |
|
44 |
/** |
45 |
* Useful static methods to provide and work with memory efficient CharSequence |
46 |
* implementations for ASCII strings. |
47 |
* |
48 |
* @since 8.3 |
49 |
* @author Alexander Simon |
50 |
* @author Vladimir Voskresensky |
51 |
*/ |
52 |
public final class CharSequences { |
53 |
|
54 |
/** |
55 |
* Provides compact char sequence object like {@link String#String(char[], int, int)} |
56 |
*/ |
57 |
public static CharSequence create(char buf[], int start, int count) { |
58 |
if (start < 0) { |
59 |
throw new StringIndexOutOfBoundsException(start); |
60 |
} |
61 |
if (count < 0) { |
62 |
throw new StringIndexOutOfBoundsException(count); |
63 |
} |
64 |
// Note: offset or count might be near -1>>>1. |
65 |
if (start > buf.length - count) { |
66 |
throw new StringIndexOutOfBoundsException(start + count); |
67 |
} |
68 |
int n = count; |
69 |
if (n == 0) { |
70 |
// special constant shared among all empty char sequences |
71 |
return EMPTY; |
72 |
} |
73 |
byte[] b = new byte[n]; |
74 |
boolean bytes = true; |
75 |
int o; |
76 |
// check 2 bytes vs 1 byte chars |
77 |
for (int i = 0; i < n; i++) { |
78 |
o = buf[start + i]; |
79 |
if ((o & 0xFF) != o) { |
80 |
// can not compact this char sequence |
81 |
bytes = false; |
82 |
break; |
83 |
} |
84 |
b[i] = (byte) o; |
85 |
} |
86 |
if (bytes) { |
87 |
return createFromBytes(b, n); |
88 |
} |
89 |
char[] v = new char[count]; |
90 |
System.arraycopy(buf, start, v, 0, count); |
91 |
return new CharSequenceKey(v); |
92 |
} |
93 |
|
94 |
/** |
95 |
* Provides compact char sequence object like {@link String#String(String)} |
96 |
*/ |
97 |
public static CharSequence create(CharSequence s) { |
98 |
if (s == null) { |
99 |
return null; |
100 |
} |
101 |
// already compact instance |
102 |
if (s instanceof CompactCharSequence) { |
103 |
return s; |
104 |
} |
105 |
int n = s.length(); |
106 |
if (n == 0) { |
107 |
// special constant shared among all empty char sequences |
108 |
return EMPTY; |
109 |
} |
110 |
byte[] b = new byte[n]; |
111 |
boolean bytes = true; |
112 |
int o; |
113 |
for (int i = 0; i < n; i++) { |
114 |
o = s.charAt(i); |
115 |
if ((o & 0xFF) != o) { |
116 |
bytes = false; |
117 |
break; |
118 |
} |
119 |
b[i] = (byte) o; |
120 |
} |
121 |
if (bytes) { |
122 |
return createFromBytes(b, n); |
123 |
} |
124 |
char[] v = new char[n]; |
125 |
for (int i = 0; i < n; i++) { |
126 |
v[i] = s.charAt(i); |
127 |
} |
128 |
return new CharSequenceKey(v); |
129 |
} |
130 |
|
131 |
/** |
132 |
* Provides optimized char sequences comparator |
133 |
* @param ignoreCase true to get case insensitive comparator |
134 |
* false to get case sensitive comparator |
135 |
* @return comparator |
136 |
*/ |
137 |
public static Comparator<CharSequence> comparator(boolean ignoreCase) { |
138 |
return ignoreCase ? ComparatorIgnoreCase : Comparator; |
139 |
} |
140 |
|
141 |
/** |
142 |
* Returns object to represent empty sequence "" |
143 |
* @return char sequence to represent empty sequence |
144 |
*/ |
145 |
public static CharSequence empty() { |
146 |
return EMPTY; |
147 |
} |
148 |
|
149 |
/** |
150 |
* Predicate to check if provides char sequence is based on compact implementation |
151 |
* @param cs char sequence object to check |
152 |
* @return true if compact implementation, false otherwise |
153 |
*/ |
154 |
public static boolean isCompact(CharSequence cs) { |
155 |
return cs instanceof CompactCharSequence; |
156 |
} |
157 |
|
158 |
/** |
159 |
* Implementation of {@link String#indexOf(String)} for character sequences. |
160 |
*/ |
161 |
public static int indexOf(CharSequence text, CharSequence seq) { |
162 |
return indexOf(text, seq, 0); |
163 |
} |
164 |
|
165 |
/** |
166 |
* Implementation of {@link String#indexOf(String,int)} for character sequences. |
167 |
*/ |
168 |
public static int indexOf(CharSequence text, CharSequence seq, int fromIndex) { |
169 |
int textLength = text.length(); |
170 |
int seqLength = seq.length(); |
171 |
if (fromIndex >= textLength) { |
172 |
return (seqLength == 0 ? textLength : -1); |
173 |
} |
174 |
if (fromIndex < 0) { |
175 |
fromIndex = 0; |
176 |
} |
177 |
if (seqLength == 0) { |
178 |
return fromIndex; |
179 |
} |
180 |
|
181 |
char first = seq.charAt(0); |
182 |
int max = textLength - seqLength; |
183 |
|
184 |
for (int i = fromIndex; i <= max; i++) { |
185 |
// look for first character |
186 |
if (text.charAt(i) != first) { |
187 |
while (++i <= max && text.charAt(i) != first) { |
188 |
} |
189 |
} |
190 |
|
191 |
// found first character, now look at the rest of seq |
192 |
if (i <= max) { |
193 |
int j = i + 1; |
194 |
int end = j + seqLength - 1; |
195 |
for (int k = 1; j < end && text.charAt(j) == seq.charAt(k); j++, k++) { |
196 |
} |
197 |
if (j == end) { |
198 |
// found whole sequence |
199 |
return i; |
200 |
} |
201 |
} |
202 |
} |
203 |
return -1; |
204 |
} |
205 |
|
206 |
private static CompactCharSequence createFromBytes(byte[] b, int n) { |
207 |
if (n < 8) { |
208 |
return new Fixed_0_7(b, n); |
209 |
} else if (n < 16) { |
210 |
return new Fixed_8_15(b, n); |
211 |
} else if (n < 24) { |
212 |
return new Fixed_16_23(b, n); |
213 |
} |
214 |
return new CharSequenceKey(b); |
215 |
} |
216 |
|
217 |
//////////////////////////////////////////////////////////////////////////////// |
218 |
// Memory efficient implementations of CharSequence |
219 |
// Comparision between Fixed and String memory consumption: |
220 |
// 32-bit JVM |
221 |
//String String CharSequence |
222 |
//Length Size Size |
223 |
//1..2 40 16 |
224 |
//3..6 48 16 |
225 |
//7..7 56 16 |
226 |
//8..10 56 24 |
227 |
//11..14 64 24 |
228 |
//15..15 72 24 |
229 |
//16..18 72 32 |
230 |
//19..22 80 32 |
231 |
//23..23 88 32 |
232 |
//24..26 88 56 |
233 |
//27..28 96 56 |
234 |
//29..30 96 64 |
235 |
//31..34 104 64 |
236 |
//35..36 112 64 |
237 |
//37..38 112 72 |
238 |
//39..42 120 72 |
239 |
//...................... |
240 |
//79..82 - 200 112 |
241 |
// |
242 |
// 64-bit JVM |
243 |
//1 72 24 |
244 |
//2 72 24 |
245 |
//3 80 24 |
246 |
//4 80 24 |
247 |
//5 80 24 |
248 |
//6 80 24 |
249 |
//7 88 24 |
250 |
//8 88 32 |
251 |
//9 88 32 |
252 |
//11 96 32 |
253 |
//13 96 32 |
254 |
//15 104 32 |
255 |
//16 104 40 |
256 |
//17 104 40 |
257 |
//18 112 40 |
258 |
//19 112 40 |
259 |
//20 112 40 |
260 |
//22 120 40 |
261 |
//23 120 40 |
262 |
//24 120 80 |
263 |
//25 120 88 |
264 |
//26 128 88 |
265 |
//60 192 120 |
266 |
//100 272 160 |
267 |
|
268 |
/** |
269 |
* compact char sequence implementation for strings in range 0-7 characters |
270 |
* 8 + 2*4 = 16 bytes for all strings vs String impl occupying |
271 |
*/ |
272 |
private static final class Fixed_0_7 implements CompactCharSequence, Comparable<CharSequence> { |
273 |
|
274 |
private final int i1; |
275 |
private final int i2; |
276 |
|
277 |
@SuppressWarnings("fallthrough") |
278 |
private Fixed_0_7(byte[] b, int n) { |
279 |
int a1 = n; |
280 |
int a2 = 0; |
281 |
switch (n) { |
282 |
case 7: |
283 |
a2 += (b[6] & 0xFF) << 24; |
284 |
case 6: |
285 |
a2 += (b[5] & 0xFF) << 16; |
286 |
case 5: |
287 |
a2 += (b[4] & 0xFF) << 8; |
288 |
case 4: |
289 |
a2 += b[3] & 0xFF; |
290 |
case 3: |
291 |
a1 += (b[2] & 0xFF) << 24; |
292 |
case 2: |
293 |
a1 += (b[1] & 0xFF) << 16; |
294 |
case 1: |
295 |
a1 += (b[0] & 0xFF) << 8; |
296 |
case 0: |
297 |
break; |
298 |
default: |
299 |
throw new IllegalArgumentException(); |
300 |
} |
301 |
i1 = a1; |
302 |
i2 = a2; |
303 |
} |
304 |
|
305 |
@Override |
306 |
public int length() { |
307 |
return i1 & 0xFF; |
308 |
} |
309 |
|
310 |
@Override |
311 |
public char charAt(int index) { |
312 |
int r = 0; |
313 |
switch (index) { |
314 |
case 0: |
315 |
r = (i1 & 0xFF00) >> 8; |
316 |
break; |
317 |
case 1: |
318 |
r = (i1 & 0xFF0000) >> 16; |
319 |
break; |
320 |
case 2: |
321 |
r = (i1 >> 24) & 0xFF; |
322 |
break; |
323 |
case 3: |
324 |
r = i2 & 0xFF; |
325 |
break; |
326 |
case 4: |
327 |
r = (i2 & 0xFF00) >> 8; |
328 |
break; |
329 |
case 5: |
330 |
r = (i2 & 0xFF0000) >> 16; |
331 |
break; |
332 |
case 6: |
333 |
r = (i2 >> 24) & 0xFF; |
334 |
break; |
335 |
} |
336 |
return (char) r; |
337 |
} |
338 |
|
339 |
@Override |
340 |
public String toString() { |
341 |
int n = length(); |
342 |
char[] r = new char[n]; |
343 |
for (int i = 0; i < n; i++) { |
344 |
r[i] = charAt(i); |
345 |
} |
346 |
return new String(r); |
347 |
} |
348 |
|
349 |
@Override |
350 |
public boolean equals(Object object) { |
351 |
if (this == object) { |
352 |
return true; |
353 |
} |
354 |
if (object instanceof Fixed_0_7) { |
355 |
Fixed_0_7 otherString = (Fixed_0_7) object; |
356 |
return i1 == otherString.i1 && i2 == otherString.i2; |
357 |
} |
358 |
return false; |
359 |
} |
360 |
|
361 |
@Override |
362 |
public int hashCode() { |
363 |
int hash = 0; |
364 |
for (int i = 0; i < length(); i++) { |
365 |
hash = 31 * hash + charAt(i); |
366 |
} |
367 |
return hash; |
368 |
// return (i1 >> 4) + (i1 >> 8) + (i2 << 5) - i2; |
369 |
} |
370 |
|
371 |
@Override |
372 |
public CharSequence subSequence(int start, int end) { |
373 |
return CharSequences.create(toString().substring(start, end)); |
374 |
} |
375 |
|
376 |
@Override |
377 |
public int compareTo(CharSequence o) { |
378 |
return Comparator.compare(this, o); |
379 |
} |
380 |
} |
381 |
|
382 |
/** |
383 |
* compact char sequence implementation for strings in range 8-15 characters |
384 |
* size: 8 + 4*4 = 24 bytes for all strings vs String impl occupying |
385 |
*/ |
386 |
private static final class Fixed_8_15 implements CompactCharSequence, Comparable<CharSequence> { |
387 |
|
388 |
private final int i1; |
389 |
private final int i2; |
390 |
private final int i3; |
391 |
private final int i4; |
392 |
|
393 |
@SuppressWarnings("fallthrough") |
394 |
private Fixed_8_15(byte[] b, int n) { |
395 |
int a1 = n; |
396 |
int a2 = 0; |
397 |
int a3 = 0; |
398 |
int a4 = 0; |
399 |
switch (n) { |
400 |
case 15: |
401 |
a4 += (b[14] & 0xFF) << 24; |
402 |
case 14: |
403 |
a4 += (b[13] & 0xFF) << 16; |
404 |
case 13: |
405 |
a4 += (b[12] & 0xFF) << 8; |
406 |
case 12: |
407 |
a4 += b[11] & 0xFF; |
408 |
case 11: |
409 |
a3 += (b[10] & 0xFF) << 24; |
410 |
case 10: |
411 |
a3 += (b[9] & 0xFF) << 16; |
412 |
case 9: |
413 |
a3 += (b[8] & 0xFF) << 8; |
414 |
case 8: |
415 |
a3 += b[7] & 0xFF; |
416 |
case 7: |
417 |
a2 += (b[6] & 0xFF) << 24; |
418 |
case 6: |
419 |
a2 += (b[5] & 0xFF) << 16; |
420 |
case 5: |
421 |
a2 += (b[4] & 0xFF) << 8; |
422 |
case 4: |
423 |
a2 += b[3] & 0xFF; |
424 |
case 3: |
425 |
a1 += (b[2] & 0xFF) << 24; |
426 |
case 2: |
427 |
a1 += (b[1] & 0xFF) << 16; |
428 |
case 1: |
429 |
a1 += (b[0] & 0xFF) << 8; |
430 |
case 0: |
431 |
break; |
432 |
default: |
433 |
throw new IllegalArgumentException(); |
434 |
} |
435 |
i1 = a1; |
436 |
i2 = a2; |
437 |
i3 = a3; |
438 |
i4 = a4; |
439 |
} |
440 |
|
441 |
@Override |
442 |
public int length() { |
443 |
return i1 & 0xFF; |
444 |
} |
445 |
|
446 |
@Override |
447 |
public char charAt(int index) { |
448 |
int r = 0; |
449 |
switch (index) { |
450 |
case 0: |
451 |
r = (i1 & 0xFF00) >> 8; |
452 |
break; |
453 |
case 1: |
454 |
r = (i1 & 0xFF0000) >> 16; |
455 |
break; |
456 |
case 2: |
457 |
r = (i1 >> 24) & 0xFF; |
458 |
break; |
459 |
case 3: |
460 |
r = i2 & 0xFF; |
461 |
break; |
462 |
case 4: |
463 |
r = (i2 & 0xFF00) >> 8; |
464 |
break; |
465 |
case 5: |
466 |
r = (i2 & 0xFF0000) >> 16; |
467 |
break; |
468 |
case 6: |
469 |
r = (i2 >> 24) & 0xFF; |
470 |
break; |
471 |
case 7: |
472 |
r = i3 & 0xFF; |
473 |
break; |
474 |
case 8: |
475 |
r = (i3 & 0xFF00) >> 8; |
476 |
break; |
477 |
case 9: |
478 |
r = (i3 & 0xFF0000) >> 16; |
479 |
break; |
480 |
case 10: |
481 |
r = (i3 >> 24) & 0xFF; |
482 |
break; |
483 |
case 11: |
484 |
r = i4 & 0xFF; |
485 |
break; |
486 |
case 12: |
487 |
r = (i4 & 0xFF00) >> 8; |
488 |
break; |
489 |
case 13: |
490 |
r = (i4 & 0xFF0000) >> 16; |
491 |
break; |
492 |
case 14: |
493 |
r = (i4 >> 24) & 0xFF; |
494 |
break; |
495 |
} |
496 |
return (char) r; |
497 |
} |
498 |
|
499 |
@Override |
500 |
public String toString() { |
501 |
int n = length(); |
502 |
char[] r = new char[n]; |
503 |
for (int i = 0; i < n; i++) { |
504 |
r[i] = charAt(i); |
505 |
} |
506 |
return new String(r); |
507 |
} |
508 |
|
509 |
@Override |
510 |
public boolean equals(Object object) { |
511 |
if (this == object) { |
512 |
return true; |
513 |
} |
514 |
if (object instanceof Fixed_8_15) { |
515 |
Fixed_8_15 otherString = (Fixed_8_15) object; |
516 |
return i1 == otherString.i1 && i2 == otherString.i2 && i3 == otherString.i3 && i4 == otherString.i4; |
517 |
} |
518 |
return false; |
519 |
} |
520 |
|
521 |
@Override |
522 |
public int hashCode() { |
523 |
return i1 + 31 * (i2 + 31 * (i3 + 31 * i4)); |
524 |
} |
525 |
|
526 |
@Override |
527 |
public CharSequence subSequence(int start, int end) { |
528 |
return CharSequences.create(toString().substring(start, end)); |
529 |
} |
530 |
|
531 |
@Override |
532 |
public int compareTo(CharSequence o) { |
533 |
return Comparator.compare(this, o); |
534 |
} |
535 |
} |
536 |
|
537 |
/** |
538 |
* compact char sequence implementation for strings in range 16-23 characters |
539 |
* size: 8 + 3*8 = 32 bytes for all strings vs String impl occupying |
540 |
*/ |
541 |
private static final class Fixed_16_23 implements CompactCharSequence, Comparable<CharSequence> { |
542 |
|
543 |
private final long i1; |
544 |
private final long i2; |
545 |
private final long i3; |
546 |
|
547 |
@SuppressWarnings("fallthrough") |
548 |
private Fixed_16_23(byte[] b, int n) { |
549 |
long a1 = 0; |
550 |
long a2 = 0; |
551 |
long a3 = 0; |
552 |
switch (n) { |
553 |
case 23: |
554 |
a3 += (b[22] & 0xFF) << 24; |
555 |
case 22: |
556 |
a3 += (b[21] & 0xFF) << 16; |
557 |
case 21: |
558 |
a3 += (b[20] & 0xFF) << 8; |
559 |
case 20: |
560 |
a3 += (b[19] & 0xFF); |
561 |
a3 <<= 32; |
562 |
case 19: |
563 |
a3 += (b[18] & 0xFF) << 24; |
564 |
case 18: |
565 |
a3 += (b[17] & 0xFF) << 16; |
566 |
case 17: |
567 |
a3 += (b[16] & 0xFF) << 8; |
568 |
case 16: |
569 |
a3 += b[15] & 0xFF; |
570 |
case 15: |
571 |
a2 += (b[14] & 0xFF) << 24; |
572 |
case 14: |
573 |
a2 += (b[13] & 0xFF) << 16; |
574 |
case 13: |
575 |
a2 += (b[12] & 0xFF) << 8; |
576 |
case 12: |
577 |
a2 += (b[11] & 0xFF); |
578 |
a2 <<= 32; |
579 |
case 11: |
580 |
a2 += (b[10] & 0xFF) << 24; |
581 |
case 10: |
582 |
a2 += (b[9] & 0xFF) << 16; |
583 |
case 9: |
584 |
a2 += (b[8] & 0xFF) << 8; |
585 |
case 8: |
586 |
a2 += b[7] & 0xFF; |
587 |
case 7: |
588 |
a1 += (b[6] & 0xFF) << 24; |
589 |
case 6: |
590 |
a1 += (b[5] & 0xFF) << 16; |
591 |
case 5: |
592 |
a1 += (b[4] & 0xFF) << 8; |
593 |
case 4: |
594 |
a1 += (b[3] & 0xFF); |
595 |
a1 <<= 32; |
596 |
case 3: |
597 |
a1 += (b[2] & 0xFF) << 24; |
598 |
case 2: |
599 |
a1 += (b[1] & 0xFF) << 16; |
600 |
case 1: |
601 |
a1 += (b[0] & 0xFF) << 8; |
602 |
case 0: |
603 |
a1 += n; |
604 |
break; |
605 |
default: |
606 |
throw new IllegalArgumentException(); |
607 |
} |
608 |
i1 = a1; |
609 |
i2 = a2; |
610 |
i3 = a3; |
611 |
} |
612 |
|
613 |
@Override |
614 |
public int length() { |
615 |
return (int) (i1 & 0xFF); |
616 |
} |
617 |
|
618 |
@Override |
619 |
public char charAt(int index) { |
620 |
int r = 0; |
621 |
switch (index) { |
622 |
case 0: |
623 |
r = (int) ((i1 >> 8) & 0xFFL); |
624 |
break; |
625 |
case 1: |
626 |
r = (int) ((i1 >> 16) & 0xFFL); |
627 |
break; |
628 |
case 2: |
629 |
r = (int) ((i1 >> 24) & 0xFFL); |
630 |
break; |
631 |
case 3: |
632 |
r = (int) ((i1 >> 32) & 0xFFL); |
633 |
break; |
634 |
case 4: |
635 |
r = (int) ((i1 >> 40) & 0xFFL); |
636 |
break; |
637 |
case 5: |
638 |
r = (int) ((i1 >> 48) & 0xFFL); |
639 |
break; |
640 |
case 6: |
641 |
r = (int) ((i1 >> 56) & 0xFFL); |
642 |
break; |
643 |
case 7: |
644 |
r = (int) (i2 & 0xFFL); |
645 |
break; |
646 |
case 8: |
647 |
r = (int) ((i2 >> 8) & 0xFFL); |
648 |
break; |
649 |
case 9: |
650 |
r = (int) ((i2 >> 16) & 0xFFL); |
651 |
break; |
652 |
case 10: |
653 |
r = (int) ((i2 >> 24) & 0xFFL); |
654 |
break; |
655 |
case 11: |
656 |
r = (int) ((i2 >> 32) & 0xFFL); |
657 |
break; |
658 |
case 12: |
659 |
r = (int) ((i2 >> 40) & 0xFFL); |
660 |
break; |
661 |
case 13: |
662 |
r = (int) ((i2 >> 48) & 0xFFL); |
663 |
break; |
664 |
case 14: |
665 |
r = (int) ((i2 >> 56) & 0xFFL); |
666 |
break; |
667 |
case 15: |
668 |
r = (int) (i3 & 0xFFL); |
669 |
break; |
670 |
case 16: |
671 |
r = (int) ((i3 >> 8) & 0xFFL); |
672 |
break; |
673 |
case 17: |
674 |
r = (int) ((i3 >> 16) & 0xFFL); |
675 |
break; |
676 |
case 18: |
677 |
r = (int) ((i3 >> 24) & 0xFFL); |
678 |
break; |
679 |
case 19: |
680 |
r = (int) ((i3 >> 32) & 0xFFL); |
681 |
break; |
682 |
case 20: |
683 |
r = (int) ((i3 >> 40) & 0xFFL); |
684 |
break; |
685 |
case 21: |
686 |
r = (int) ((i3 >> 48) & 0xFFL); |
687 |
break; |
688 |
case 22: |
689 |
r = (int) ((i3 >> 56) & 0xFFL); |
690 |
break; |
691 |
} |
692 |
return (char) r; |
693 |
} |
694 |
|
695 |
@Override |
696 |
public String toString() { |
697 |
int n = length(); |
698 |
char[] r = new char[n]; |
699 |
for (int i = 0; i < n; i++) { |
700 |
r[i] = charAt(i); |
701 |
} |
702 |
return new String(r); |
703 |
} |
704 |
|
705 |
@Override |
706 |
public boolean equals(Object object) { |
707 |
if (this == object) { |
708 |
return true; |
709 |
} |
710 |
if (object instanceof Fixed_16_23) { |
711 |
Fixed_16_23 otherString = (Fixed_16_23) object; |
712 |
return i1 == otherString.i1 && i2 == otherString.i2 && i3 == otherString.i3; |
713 |
} |
714 |
return false; |
715 |
} |
716 |
|
717 |
@Override |
718 |
public int hashCode() { |
719 |
long res = i1 + 31 * (i2 + 31 * i3); |
720 |
res = (res + (res >> 32)) & 0xFFFFFFFFL; |
721 |
return (int) res; |
722 |
} |
723 |
|
724 |
@Override |
725 |
public CharSequence subSequence(int start, int end) { |
726 |
return CharSequences.create(toString().substring(start, end)); |
727 |
} |
728 |
|
729 |
@Override |
730 |
public int compareTo(CharSequence o) { |
731 |
return Comparator.compare(this, o); |
732 |
} |
733 |
} |
734 |
|
735 |
/** |
736 |
* compact char sequence implementation based on byte[] or char[] array |
737 |
* size: 8 + 4 + 4 (= 16 bytes) + sizeof ('value') |
738 |
*/ |
739 |
private final static class CharSequenceKey implements CompactCharSequence, Comparable<CharSequence> { |
740 |
|
741 |
private final Object value; |
742 |
private int hash; |
743 |
|
744 |
private CharSequenceKey(byte[] b) { |
745 |
value = b; |
746 |
} |
747 |
|
748 |
private CharSequenceKey(char[] v) { |
749 |
value = v; |
750 |
} |
751 |
|
752 |
@Override |
753 |
public int length() { |
754 |
if (value instanceof byte[]) { |
755 |
return ((byte[]) value).length; |
756 |
} |
757 |
return ((char[]) value).length; |
758 |
} |
759 |
|
760 |
@Override |
761 |
public char charAt(int index) { |
762 |
if (value instanceof byte[]) { |
763 |
int r = ((byte[]) value)[index] & 0xFF; |
764 |
return (char) r; |
765 |
} |
766 |
return ((char[]) value)[index]; |
767 |
} |
768 |
|
769 |
@Override |
770 |
public boolean equals(Object object) { |
771 |
if (this == object) { |
772 |
return true; |
773 |
} |
774 |
if (object instanceof CharSequenceKey) { |
775 |
CharSequenceKey otherString = (CharSequenceKey) object; |
776 |
if (hash != 0 && otherString.hash != 0) { |
777 |
if (hash != otherString.hash) { |
778 |
return false; |
779 |
} |
780 |
} |
781 |
if ((value instanceof byte[]) && (otherString.value instanceof byte[])) { |
782 |
return Arrays.equals((byte[]) value, (byte[]) otherString.value); |
783 |
} else if ((value instanceof char[]) && (otherString.value instanceof char[])) { |
784 |
return Arrays.equals((char[]) value, (char[]) otherString.value); |
785 |
} |
786 |
} |
787 |
return false; |
788 |
} |
789 |
|
790 |
@Override |
791 |
public int hashCode() { |
792 |
int h = hash; |
793 |
if (h == 0) { |
794 |
if (value instanceof byte[]) { |
795 |
byte[] v = (byte[]) value; |
796 |
int n = v.length; |
797 |
for (int i = 0; i < n; i++) { |
798 |
h = 31 * h + v[i]; |
799 |
} |
800 |
} else { |
801 |
char[] v = (char[]) value; |
802 |
int n = v.length; |
803 |
for (int i = 0; i < n; i++) { |
804 |
h = 31 * h + v[i]; |
805 |
} |
806 |
} |
807 |
hash = h; |
808 |
} |
809 |
return h; |
810 |
} |
811 |
|
812 |
@Override |
813 |
public CharSequence subSequence(int beginIndex, int endIndex) { |
814 |
return CharSequences.create(toString().substring(beginIndex, endIndex)); |
815 |
} |
816 |
|
817 |
@Override |
818 |
public String toString() { |
819 |
if (value instanceof byte[]) { |
820 |
byte[] v = (byte[]) value; |
821 |
int n = v.length; |
822 |
char[] r = new char[n]; |
823 |
for (int i = 0; i < n; i++) { |
824 |
int c = v[i] & 0xFF; |
825 |
r[i] = (char) c; |
826 |
} |
827 |
return new String(r); |
828 |
} |
829 |
char[] v = (char[]) value; |
830 |
return new String(v); |
831 |
} |
832 |
|
833 |
@Override |
834 |
public int compareTo(CharSequence o) { |
835 |
return Comparator.compare(this, o); |
836 |
} |
837 |
} |
838 |
|
839 |
private static final CompactCharSequence EMPTY = new Fixed_0_7(new byte[0], 0); |
840 |
private static final Comparator<CharSequence> Comparator = new CharSequenceComparator(); |
841 |
private static final Comparator<CharSequence> ComparatorIgnoreCase = new CharSequenceComparatorIgnoreCase(); |
842 |
|
843 |
private static class CharSequenceComparator implements Comparator<CharSequence> { |
844 |
|
845 |
@Override |
846 |
public int compare(CharSequence o1, CharSequence o2) { |
847 |
if ((o1 instanceof CharSequenceKey)) { |
848 |
if ((o2 instanceof CharSequenceKey)) { |
849 |
CharSequenceKey csk1 = (CharSequenceKey) o1; |
850 |
CharSequenceKey csk2 = (CharSequenceKey) o2; |
851 |
if ((csk1.value instanceof byte[]) |
852 |
&& (csk2.value instanceof byte[])) { |
853 |
byte[] b1 = (byte[]) csk1.value; |
854 |
byte[] b2 = (byte[]) csk2.value; |
855 |
int len1 = b1.length; |
856 |
int len2 = b2.length; |
857 |
int n = Math.min(len1, len2); |
858 |
int k = 0; |
859 |
while (k < n) { |
860 |
if (b1[k] != b2[k]) { |
861 |
return (b1[k] & 0xFF) - (b2[k] & 0xFF); |
862 |
} |
863 |
k++; |
864 |
} |
865 |
return len1 - len2; |
866 |
} |
867 |
} else { |
868 |
CharSequenceKey csk1 = (CharSequenceKey) o1; |
869 |
if ((csk1.value instanceof byte[])) { |
870 |
byte[] b1 = (byte[]) csk1.value; |
871 |
int len1 = b1.length; |
872 |
int len2 = o2.length(); |
873 |
int n = Math.min(len1, len2); |
874 |
int k = 0; |
875 |
int c1, c2; |
876 |
while (k < n) { |
877 |
c1 = b1[k] & 0xFF; |
878 |
c2 = o2.charAt(k); |
879 |
if (c1 != c2) { |
880 |
return c1 - c2; |
881 |
} |
882 |
k++; |
883 |
} |
884 |
return len1 - len2; |
885 |
} |
886 |
} |
887 |
} else if ((o2 instanceof CharSequenceKey)) { |
888 |
CharSequenceKey csk2 = (CharSequenceKey) o2; |
889 |
if ((csk2.value instanceof byte[])) { |
890 |
byte[] b2 = (byte[]) csk2.value; |
891 |
int len1 = o1.length(); |
892 |
int len2 = b2.length; |
893 |
int n = Math.min(len1, len2); |
894 |
int k = 0; |
895 |
int c1, c2; |
896 |
while (k < n) { |
897 |
c1 = o1.charAt(k); |
898 |
c2 = b2[k] & 0xFF; |
899 |
if (c1 != c2) { |
900 |
return c1 - c2; |
901 |
} |
902 |
k++; |
903 |
} |
904 |
return len1 - len2; |
905 |
} |
906 |
} |
907 |
int len1 = o1.length(); |
908 |
int len2 = o2.length(); |
909 |
int n = Math.min(len1, len2); |
910 |
int k = 0; |
911 |
while (k < n) { |
912 |
char c1 = o1.charAt(k); |
913 |
char c2 = o2.charAt(k); |
914 |
if (c1 != c2) { |
915 |
return c1 - c2; |
916 |
} |
917 |
k++; |
918 |
} |
919 |
return len1 - len2; |
920 |
} |
921 |
} |
922 |
|
923 |
private static class CharSequenceComparatorIgnoreCase implements Comparator<CharSequence> { |
924 |
|
925 |
@Override |
926 |
public int compare(CharSequence o1, CharSequence o2) { |
927 |
int n1 = o1.length(); |
928 |
int n2 = o2.length(); |
929 |
for (int i1 = 0, i2 = 0; i1 < n1 && i2 < n2; i1++, i2++) { |
930 |
char c1 = o1.charAt(i1); |
931 |
char c2 = o2.charAt(i2); |
932 |
if (c1 != c2) { |
933 |
c1 = Character.toUpperCase(c1); |
934 |
c2 = Character.toUpperCase(c2); |
935 |
if (c1 != c2) { |
936 |
c1 = Character.toLowerCase(c1); |
937 |
c2 = Character.toLowerCase(c2); |
938 |
if (c1 != c2) { |
939 |
return c1 - c2; |
940 |
} |
941 |
} |
942 |
} |
943 |
} |
944 |
return n1 - n2; |
945 |
} |
946 |
} |
947 |
|
948 |
/** |
949 |
* marker interface for compact char sequence implementations |
950 |
*/ |
951 |
private interface CompactCharSequence extends CharSequence { |
952 |
} |
953 |
|
954 |
/** |
955 |
* private constructor for utilities class |
956 |
*/ |
957 |
private CharSequences() { |
958 |
} |
959 |
} |