This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 183162
Collapse All | Expand All

(-)a/openide.util/manifest.mf (-1 / +1 lines)
Lines 1-5 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.openide.util
2
OpenIDE-Module: org.openide.util
3
OpenIDE-Module-Localizing-Bundle: org/openide/util/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/openide/util/Bundle.properties
4
OpenIDE-Module-Specification-Version: 8.2
4
OpenIDE-Module-Specification-Version: 8.3
5
5
(-)a/openide.util/src/org/openide/util/CharSequences.java (+908 lines)
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
 * utilities to provide and work with compact CharSequence implementations
46
 *
47
 * @since 8.3
48
 * @author Alexander Simon
49
 * @author Vladiir Voskresensky
50
 */
51
public class CharSequences {
52
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_1_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
     * compact char sequence implementation for strings in range 1-7 characters
219
     * 8 + 2*4 = 16 bytes for all strings vs String impl occupying 
220
     */
221
    private static final class Fixed_1_7 implements CompactCharSequence, Comparable<CharSequence> {
222
223
        private final int i1;
224
        private final int i2;
225
226
        @SuppressWarnings("fallthrough")
227
        private Fixed_1_7(byte[] b, int n) {
228
            int a1 = n;
229
            int a2 = 0;
230
            switch (n) {
231
                case 7:
232
                    a2 += (b[6] & 0xFF) << 24;
233
                case 6:
234
                    a2 += (b[5] & 0xFF) << 16;
235
                case 5:
236
                    a2 += (b[4] & 0xFF) << 8;
237
                case 4:
238
                    a2 += b[3] & 0xFF;
239
                case 3:
240
                    a1 += (b[2] & 0xFF) << 24;
241
                case 2:
242
                    a1 += (b[1] & 0xFF) << 16;
243
                case 1:
244
                    a1 += (b[0] & 0xFF) << 8;
245
                case 0:
246
                    break;
247
                default:
248
                    throw new IllegalArgumentException();
249
            }
250
            i1 = a1;
251
            i2 = a2;
252
        }
253
254
        @Override
255
        public int length() {
256
            return i1 & 0xFF;
257
        }
258
259
        @Override
260
        public char charAt(int index) {
261
            int r = 0;
262
            switch (index) {
263
                case 0:
264
                    r = (i1 & 0xFF00) >> 8;
265
                    break;
266
                case 1:
267
                    r = (i1 & 0xFF0000) >> 16;
268
                    break;
269
                case 2:
270
                    r = (i1 >> 24) & 0xFF;
271
                    break;
272
                case 3:
273
                    r = i2 & 0xFF;
274
                    break;
275
                case 4:
276
                    r = (i2 & 0xFF00) >> 8;
277
                    break;
278
                case 5:
279
                    r = (i2 & 0xFF0000) >> 16;
280
                    break;
281
                case 6:
282
                    r = (i2 >> 24) & 0xFF;
283
                    break;
284
            }
285
            return (char) r;
286
        }
287
288
        @Override
289
        public String toString() {
290
            int n = length();
291
            char[] r = new char[n];
292
            for (int i = 0; i < n; i++) {
293
                r[i] = charAt(i);
294
            }
295
            return new String(r);
296
        }
297
298
        @Override
299
        public boolean equals(Object object) {
300
            if (this == object) {
301
                return true;
302
            }
303
            if (object instanceof Fixed_1_7) {
304
                Fixed_1_7 otherString = (Fixed_1_7) object;
305
                return i1 == otherString.i1 && i2 == otherString.i2;
306
            }
307
            return false;
308
        }
309
310
        @Override
311
        public int hashCode() {
312
            int hash = 0;
313
            for (int i = 0; i < length(); i++) {
314
                hash = 31 * hash + charAt(i);
315
            }
316
            return hash;
317
            //            return (i1 >> 4) + (i1 >> 8) + (i2 << 5) - i2;
318
        }
319
320
        @Override
321
        public CharSequence subSequence(int start, int end) {
322
            return CharSequences.create(toString().substring(start, end));
323
        }
324
325
        @Override
326
        public int compareTo(CharSequence o) {
327
            return Comparator.compare(this, o);
328
        }
329
    }
330
331
    /**
332
     * compact char sequence implementation for strings in range 8-15 characters
333
     * size: 8 + 4*4 = 24 bytes for all strings vs String impl occupying
334
     */
335
    private static final class Fixed_8_15 implements CompactCharSequence, Comparable<CharSequence> {
336
337
        private final int i1;
338
        private final int i2;
339
        private final int i3;
340
        private final int i4;
341
342
        @SuppressWarnings("fallthrough")
343
        private Fixed_8_15(byte[] b, int n) {
344
            int a1 = n;
345
            int a2 = 0;
346
            int a3 = 0;
347
            int a4 = 0;
348
            switch (n) {
349
                case 15:
350
                    a4 += (b[14] & 0xFF) << 24;
351
                case 14:
352
                    a4 += (b[13] & 0xFF) << 16;
353
                case 13:
354
                    a4 += (b[12] & 0xFF) << 8;
355
                case 12:
356
                    a4 += b[11] & 0xFF;
357
                case 11:
358
                    a3 += (b[10] & 0xFF) << 24;
359
                case 10:
360
                    a3 += (b[9] & 0xFF) << 16;
361
                case 9:
362
                    a3 += (b[8] & 0xFF) << 8;
363
                case 8:
364
                    a3 += b[7] & 0xFF;
365
                case 7:
366
                    a2 += (b[6] & 0xFF) << 24;
367
                case 6:
368
                    a2 += (b[5] & 0xFF) << 16;
369
                case 5:
370
                    a2 += (b[4] & 0xFF) << 8;
371
                case 4:
372
                    a2 += b[3] & 0xFF;
373
                case 3:
374
                    a1 += (b[2] & 0xFF) << 24;
375
                case 2:
376
                    a1 += (b[1] & 0xFF) << 16;
377
                case 1:
378
                    a1 += (b[0] & 0xFF) << 8;
379
                case 0:
380
                    break;
381
                default:
382
                    throw new IllegalArgumentException();
383
            }
384
            i1 = a1;
385
            i2 = a2;
386
            i3 = a3;
387
            i4 = a4;
388
        }
389
390
        @Override
391
        public int length() {
392
            return i1 & 0xFF;
393
        }
394
395
        @Override
396
        public char charAt(int index) {
397
            int r = 0;
398
            switch (index) {
399
                case 0:
400
                    r = (i1 & 0xFF00) >> 8;
401
                    break;
402
                case 1:
403
                    r = (i1 & 0xFF0000) >> 16;
404
                    break;
405
                case 2:
406
                    r = (i1 >> 24) & 0xFF;
407
                    break;
408
                case 3:
409
                    r = i2 & 0xFF;
410
                    break;
411
                case 4:
412
                    r = (i2 & 0xFF00) >> 8;
413
                    break;
414
                case 5:
415
                    r = (i2 & 0xFF0000) >> 16;
416
                    break;
417
                case 6:
418
                    r = (i2 >> 24) & 0xFF;
419
                    break;
420
                case 7:
421
                    r = i3 & 0xFF;
422
                    break;
423
                case 8:
424
                    r = (i3 & 0xFF00) >> 8;
425
                    break;
426
                case 9:
427
                    r = (i3 & 0xFF0000) >> 16;
428
                    break;
429
                case 10:
430
                    r = (i3 >> 24) & 0xFF;
431
                    break;
432
                case 11:
433
                    r = i4 & 0xFF;
434
                    break;
435
                case 12:
436
                    r = (i4 & 0xFF00) >> 8;
437
                    break;
438
                case 13:
439
                    r = (i4 & 0xFF0000) >> 16;
440
                    break;
441
                case 14:
442
                    r = (i4 >> 24) & 0xFF;
443
                    break;
444
            }
445
            return (char) r;
446
        }
447
448
        @Override
449
        public String toString() {
450
            int n = length();
451
            char[] r = new char[n];
452
            for (int i = 0; i < n; i++) {
453
                r[i] = charAt(i);
454
            }
455
            return new String(r);
456
        }
457
458
        @Override
459
        public boolean equals(Object object) {
460
            if (this == object) {
461
                return true;
462
            }
463
            if (object instanceof Fixed_8_15) {
464
                Fixed_8_15 otherString = (Fixed_8_15) object;
465
                return i1 == otherString.i1 && i2 == otherString.i2 && i3 == otherString.i3 && i4 == otherString.i4;
466
            }
467
            return false;
468
        }
469
470
        @Override
471
        public int hashCode() {
472
            return i1 + 31 * (i2 + 31 * (i3 + 31 * i4));
473
        }
474
475
        @Override
476
        public CharSequence subSequence(int start, int end) {
477
            return CharSequences.create(toString().substring(start, end));
478
        }
479
480
        @Override
481
        public int compareTo(CharSequence o) {
482
            return Comparator.compare(this, o);
483
        }
484
    }
485
486
    /**
487
     * compact char sequence implementation for strings in range 16-23 characters
488
     * size: 8 + 3*8 = 32 bytes for all strings vs String impl occupying 
489
     */
490
    private static final class Fixed_16_23 implements CompactCharSequence, Comparable<CharSequence> {
491
492
        private final long i1;
493
        private final long i2;
494
        private final long i3;
495
496
        @SuppressWarnings("fallthrough")
497
        private Fixed_16_23(byte[] b, int n) {
498
            long a1 = 0;
499
            long a2 = 0;
500
            long a3 = 0;
501
            switch (n) {
502
                case 23:
503
                    a3 += (b[22] & 0xFF) << 24;
504
                case 22:
505
                    a3 += (b[21] & 0xFF) << 16;
506
                case 21:
507
                    a3 += (b[20] & 0xFF) << 8;
508
                case 20:
509
                    a3 += (b[19] & 0xFF);
510
                    a3 <<= 32;
511
                case 19:
512
                    a3 += (b[18] & 0xFF) << 24;
513
                case 18:
514
                    a3 += (b[17] & 0xFF) << 16;
515
                case 17:
516
                    a3 += (b[16] & 0xFF) << 8;
517
                case 16:
518
                    a3 += b[15] & 0xFF;
519
                case 15:
520
                    a2 += (b[14] & 0xFF) << 24;
521
                case 14:
522
                    a2 += (b[13] & 0xFF) << 16;
523
                case 13:
524
                    a2 += (b[12] & 0xFF) << 8;
525
                case 12:
526
                    a2 += (b[11] & 0xFF);
527
                    a2 <<= 32;
528
                case 11:
529
                    a2 += (b[10] & 0xFF) << 24;
530
                case 10:
531
                    a2 += (b[9] & 0xFF) << 16;
532
                case 9:
533
                    a2 += (b[8] & 0xFF) << 8;
534
                case 8:
535
                    a2 += b[7] & 0xFF;
536
                case 7:
537
                    a1 += (b[6] & 0xFF) << 24;
538
                case 6:
539
                    a1 += (b[5] & 0xFF) << 16;
540
                case 5:
541
                    a1 += (b[4] & 0xFF) << 8;
542
                case 4:
543
                    a1 += (b[3] & 0xFF);
544
                    a1 <<= 32;
545
                case 3:
546
                    a1 += (b[2] & 0xFF) << 24;
547
                case 2:
548
                    a1 += (b[1] & 0xFF) << 16;
549
                case 1:
550
                    a1 += (b[0] & 0xFF) << 8;
551
                case 0:
552
                    a1 += n;
553
                    break;
554
                default:
555
                    throw new IllegalArgumentException();
556
            }
557
            i1 = a1;
558
            i2 = a2;
559
            i3 = a3;
560
        }
561
562
        @Override
563
        public int length() {
564
            return (int) (i1 & 0xFF);
565
        }
566
567
        @Override
568
        public char charAt(int index) {
569
            int r = 0;
570
            switch (index) {
571
                case 0:
572
                    r = (int) ((i1 >> 8) & 0xFFL);
573
                    break;
574
                case 1:
575
                    r = (int) ((i1 >> 16) & 0xFFL);
576
                    break;
577
                case 2:
578
                    r = (int) ((i1 >> 24) & 0xFFL);
579
                    break;
580
                case 3:
581
                    r = (int) ((i1 >> 32) & 0xFFL);
582
                    break;
583
                case 4:
584
                    r = (int) ((i1 >> 40) & 0xFFL);
585
                    break;
586
                case 5:
587
                    r = (int) ((i1 >> 48) & 0xFFL);
588
                    break;
589
                case 6:
590
                    r = (int) ((i1 >> 56) & 0xFFL);
591
                    break;
592
                case 7:
593
                    r = (int) (i2 & 0xFFL);
594
                    break;
595
                case 8:
596
                    r = (int) ((i2 >> 8) & 0xFFL);
597
                    break;
598
                case 9:
599
                    r = (int) ((i2 >> 16) & 0xFFL);
600
                    break;
601
                case 10:
602
                    r = (int) ((i2 >> 24) & 0xFFL);
603
                    break;
604
                case 11:
605
                    r = (int) ((i2 >> 32) & 0xFFL);
606
                    break;
607
                case 12:
608
                    r = (int) ((i2 >> 40) & 0xFFL);
609
                    break;
610
                case 13:
611
                    r = (int) ((i2 >> 48) & 0xFFL);
612
                    break;
613
                case 14:
614
                    r = (int) ((i2 >> 56) & 0xFFL);
615
                    break;
616
                case 15:
617
                    r = (int) (i3 & 0xFFL);
618
                    break;
619
                case 16:
620
                    r = (int) ((i3 >> 8) & 0xFFL);
621
                    break;
622
                case 17:
623
                    r = (int) ((i3 >> 16) & 0xFFL);
624
                    break;
625
                case 18:
626
                    r = (int) ((i3 >> 24) & 0xFFL);
627
                    break;
628
                case 19:
629
                    r = (int) ((i3 >> 32) & 0xFFL);
630
                    break;
631
                case 20:
632
                    r = (int) ((i3 >> 40) & 0xFFL);
633
                    break;
634
                case 21:
635
                    r = (int) ((i3 >> 48) & 0xFFL);
636
                    break;
637
                case 22:
638
                    r = (int) ((i3 >> 56) & 0xFFL);
639
                    break;
640
            }
641
            return (char) r;
642
        }
643
644
        @Override
645
        public String toString() {
646
            int n = length();
647
            char[] r = new char[n];
648
            for (int i = 0; i < n; i++) {
649
                r[i] = charAt(i);
650
            }
651
            return new String(r);
652
        }
653
654
        @Override
655
        public boolean equals(Object object) {
656
            if (this == object) {
657
                return true;
658
            }
659
            if (object instanceof Fixed_16_23) {
660
                Fixed_16_23 otherString = (Fixed_16_23) object;
661
                return i1 == otherString.i1 && i2 == otherString.i2 && i3 == otherString.i3;
662
            }
663
            return false;
664
        }
665
666
        @Override
667
        public int hashCode() {
668
            long res = i1 + 31 * (i2 + 31 * i3);
669
            res = (res + (res >> 32)) & 0xFFFFFFFFL;
670
            return (int) res;
671
        }
672
673
        @Override
674
        public CharSequence subSequence(int start, int end) {
675
            return CharSequences.create(toString().substring(start, end));
676
        }
677
678
        @Override
679
        public int compareTo(CharSequence o) {
680
            return Comparator.compare(this, o);
681
        }
682
    }
683
684
    /**
685
     * compact char sequence implementation based on byte[] or char[] array
686
     * size: 8 + 4 + 4 (= 16 bytes) + sizeof ('value')
687
     */
688
    private final static class CharSequenceKey implements CompactCharSequence, Comparable<CharSequence> {
689
690
        private final Object value;
691
        private int hash;
692
693
        private CharSequenceKey(byte[] b) {
694
            value = b;
695
        }
696
697
        private CharSequenceKey(char[] v) {
698
            value = v;
699
        }
700
701
        @Override
702
        public int length() {
703
            if (value instanceof byte[]) {
704
                return ((byte[]) value).length;
705
            }
706
            return ((char[]) value).length;
707
        }
708
709
        @Override
710
        public char charAt(int index) {
711
            if (value instanceof byte[]) {
712
                int r = ((byte[]) value)[index] & 0xFF;
713
                return (char) r;
714
            }
715
            return ((char[]) value)[index];
716
        }
717
718
        @Override
719
        public boolean equals(Object object) {
720
            if (this == object) {
721
                return true;
722
            }
723
            if (object instanceof CharSequenceKey) {
724
                CharSequenceKey otherString = (CharSequenceKey) object;
725
                if (hash != 0 && otherString.hash != 0) {
726
                    if (hash != otherString.hash) {
727
                        return false;
728
                    }
729
                }
730
                if ((value instanceof byte[]) && (otherString.value instanceof byte[])) {
731
                    return Arrays.equals((byte[]) value, (byte[]) otherString.value);
732
                } else if ((value instanceof char[]) && (otherString.value instanceof char[])) {
733
                    return Arrays.equals((char[]) value, (char[]) otherString.value);
734
                }
735
            }
736
            return false;
737
        }
738
739
        @Override
740
        public int hashCode() {
741
            int h = hash;
742
            if (h == 0) {
743
                if (value instanceof byte[]) {
744
                    byte[] v = (byte[]) value;
745
                    int n = v.length;
746
                    for (int i = 0; i < n; i++) {
747
                        h = 31 * h + v[i];
748
                    }
749
                } else {
750
                    char[] v = (char[]) value;
751
                    int n = v.length;
752
                    for (int i = 0; i < n; i++) {
753
                        h = 31 * h + v[i];
754
                    }
755
                }
756
                hash = h;
757
            }
758
            return h;
759
        }
760
761
        @Override
762
        public CharSequence subSequence(int beginIndex, int endIndex) {
763
            return CharSequences.create(toString().substring(beginIndex, endIndex));
764
        }
765
766
        @Override
767
        public String toString() {
768
            if (value instanceof byte[]) {
769
                byte[] v = (byte[]) value;
770
                int n = v.length;
771
                char[] r = new char[n];
772
                for (int i = 0; i < n; i++) {
773
                    int c = v[i] & 0xFF;
774
                    r[i] = (char) c;
775
                }
776
                return new String(r);
777
            }
778
            char[] v = (char[]) value;
779
            return new String(v);
780
        }
781
782
        @Override
783
        public int compareTo(CharSequence o) {
784
            return Comparator.compare(this, o);
785
        }
786
    }
787
    
788
    private static final CompactCharSequence EMPTY = new CharSequenceKey(new byte[]{});
789
    private static final Comparator<CharSequence> Comparator = new CharSequenceComparator();
790
    private static final Comparator<CharSequence> ComparatorIgnoreCase = new CharSequenceComparatorIgnoreCase();
791
792
    private static class CharSequenceComparator implements Comparator<CharSequence> {
793
794
        @Override
795
        public int compare(CharSequence o1, CharSequence o2) {
796
            if ((o1 instanceof CharSequenceKey)) {
797
                if ((o2 instanceof CharSequenceKey)) {
798
                    CharSequenceKey csk1 = (CharSequenceKey) o1;
799
                    CharSequenceKey csk2 = (CharSequenceKey) o2;
800
                    if ((csk1.value instanceof byte[])
801
                            && (csk2.value instanceof byte[])) {
802
                        byte[] b1 = (byte[]) csk1.value;
803
                        byte[] b2 = (byte[]) csk2.value;
804
                        int len1 = b1.length;
805
                        int len2 = b2.length;
806
                        int n = Math.min(len1, len2);
807
                        int k = 0;
808
                        while (k < n) {
809
                            if (b1[k] != b2[k]) {
810
                                return (b1[k] & 0xFF) - (b2[k] & 0xFF);
811
                            }
812
                            k++;
813
                        }
814
                        return len1 - len2;
815
                    }
816
                } else {
817
                    CharSequenceKey csk1 = (CharSequenceKey) o1;
818
                    if ((csk1.value instanceof byte[])) {
819
                        byte[] b1 = (byte[]) csk1.value;
820
                        int len1 = b1.length;
821
                        int len2 = o2.length();
822
                        int n = Math.min(len1, len2);
823
                        int k = 0;
824
                        int c1, c2;
825
                        while (k < n) {
826
                            c1 = b1[k] & 0xFF;
827
                            c2 = o2.charAt(k);
828
                            if (c1 != c2) {
829
                                return c1 - c2;
830
                            }
831
                            k++;
832
                        }
833
                        return len1 - len2;
834
                    }
835
                }
836
            } else if ((o2 instanceof CharSequenceKey)) {
837
                CharSequenceKey csk2 = (CharSequenceKey) o2;
838
                if ((csk2.value instanceof byte[])) {
839
                    byte[] b2 = (byte[]) csk2.value;
840
                    int len1 = o1.length();
841
                    int len2 = b2.length;
842
                    int n = Math.min(len1, len2);
843
                    int k = 0;
844
                    int c1, c2;
845
                    while (k < n) {
846
                        c1 = o1.charAt(k);
847
                        c2 = b2[k] & 0xFF;
848
                        if (c1 != c2) {
849
                            return c1 - c2;
850
                        }
851
                        k++;
852
                    }
853
                    return len1 - len2;
854
                }
855
            }
856
            int len1 = o1.length();
857
            int len2 = o2.length();
858
            int n = Math.min(len1, len2);
859
            int k = 0;
860
            while (k < n) {
861
                char c1 = o1.charAt(k);
862
                char c2 = o2.charAt(k);
863
                if (c1 != c2) {
864
                    return c1 - c2;
865
                }
866
                k++;
867
            }
868
            return len1 - len2;
869
        }
870
    }
871
872
    private static class CharSequenceComparatorIgnoreCase implements Comparator<CharSequence> {
873
874
        @Override
875
        public int compare(CharSequence o1, CharSequence o2) {
876
            int n1 = o1.length();
877
            int n2 = o2.length();
878
            for (int i1 = 0, i2 = 0; i1 < n1 && i2 < n2; i1++, i2++) {
879
                char c1 = o1.charAt(i1);
880
                char c2 = o2.charAt(i2);
881
                if (c1 != c2) {
882
                    c1 = Character.toUpperCase(c1);
883
                    c2 = Character.toUpperCase(c2);
884
                    if (c1 != c2) {
885
                        c1 = Character.toLowerCase(c1);
886
                        c2 = Character.toLowerCase(c2);
887
                        if (c1 != c2) {
888
                            return c1 - c2;
889
                        }
890
                    }
891
                }
892
            }
893
            return n1 - n2;
894
        }
895
    }
896
897
    /**
898
     * marker interface for compact char sequence implementations
899
     */
900
    private interface CompactCharSequence extends CharSequence {
901
    }
902
903
    /**
904
     * private constructor for utilities class
905
     */
906
    private CharSequences() {
907
    }
908
}
(-)a/openide.util/test/unit/src/org/openide/util/CharSequencesTest.java (+174 lines)
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
40
package org.openide.util;
41
42
import org.netbeans.junit.NbTestCase;
43
import java.util.Comparator;
44
import org.junit.Test;
45
46
/**
47
 *
48
 * @author Vladimir Voskresensky
49
 */
50
public class CharSequencesTest extends NbTestCase {
51
52
    public CharSequencesTest() {
53
        super("CharSequencesTest");
54
    }
55
56
    /**
57
     * Test of create method, of class CharSequences.
58
     */
59
    @Test
60
    public void testCreate_3args() {
61
        char[] buf = new char[] {'H', 'e', 'l', 'l', 'o', ',', ' ', 'P', 'l', 'a', 't', 'f', 'o', 'r', 'm', '!'};
62
        for (int start = 0; start < buf.length; start++) {
63
            for (int count = 1; count < buf.length - start; count++) {
64
                CharSequence expResult = new String(buf, start, count);
65
                CharSequence result = CharSequences.create(buf, start, count);
66
                assertEquals("["+start+", " + count+"]", expResult, result.toString());
67
            }
68
        }
69
    }
70
71
    /**
72
     * Test of create method, of class CharSequences.
73
     */
74
    @Test
75
    public void testCreate_CharSequence() {
76
        String[] strs = new String[] { "", "1234567", "123456789012345", "12345678901234567890123", "123456789012345678901234" };
77
        for (String str : strs) {
78
            assertEquals(str, CharSequences.create(str).toString());
79
            assertEquals(CharSequences.create(str).toString(), str);
80
            assertEquals(CharSequences.create(str).toString(), CharSequences.create(str).toString());
81
        }
82
    }
83
84
    /**
85
     * Test of comparator method, of class CharSequences.
86
     */
87
    @Test
88
    public void testCaseSensitiveComparator() {
89
        Comparator<CharSequence> comparator = CharSequences.comparator(false);
90
        String[] strs = new String[]{"", "1234567", "123456789012345", "12345678901234567890123", "123456789012345678901234"};
91
        for (String str : strs) {
92
            assertEquals(0, comparator.compare(str, CharSequences.create(str)));
93
            assertEquals(0, comparator.compare(CharSequences.create(str), str));
94
            assertEquals(0, comparator.compare(CharSequences.create(str), CharSequences.create(str)));
95
        }
96
    }
97
98
    /**
99
     * Test of comparator method, of class CharSequences.
100
     */
101
    @Test
102
    public void testCaseInsensitiveComparator() {
103
        Comparator<CharSequence> comparator = CharSequences.comparator(true);
104
        String[] strs = new String[]{"", "1234567", "123456789012345", "12345678901234567890123", "123456789012345678901234"};
105
        for (int i = 0; i < strs.length; i++) {
106
            String str = strs[i];
107
            String upperStr = str.toUpperCase();
108
            String lowerStr = str.toLowerCase();
109
            assertEquals(0, comparator.compare(str, CharSequences.create(str)));
110
            assertEquals(0, comparator.compare(CharSequences.create(str), str));
111
            assertEquals(0, comparator.compare(CharSequences.create(str), CharSequences.create(str)));
112
            assertEquals(0, comparator.compare(upperStr, CharSequences.create(str)));
113
            assertEquals(0, comparator.compare(CharSequences.create(str), upperStr));
114
            assertEquals(0, comparator.compare(CharSequences.create(upperStr), CharSequences.create(str)));
115
            assertEquals(0, comparator.compare(lowerStr, CharSequences.create(str)));
116
            assertEquals(0, comparator.compare(CharSequences.create(str), lowerStr));
117
            assertEquals(0, comparator.compare(CharSequences.create(str), CharSequences.create(lowerStr)));
118
        }
119
    }
120
121
    /**
122
     * Test of empty method, of class CharSequences.
123
     */
124
    @Test
125
    public void testEmpty() {
126
        assertEquals("", CharSequences.create("").toString());
127
        assertEquals(CharSequences.create("").toString(), "");
128
        assertEquals("", CharSequences.empty().toString());
129
        assertEquals(CharSequences.empty().toString(), "");
130
        assertSame(CharSequences.empty(), CharSequences.create(""));
131
    }
132
133
    /**
134
     * Test of isCompact method, of class CharSequences.
135
     */
136
    @Test
137
    public void testIsCompact() {
138
        String[] strs = new String[]{"", "1234567", "123456789012345", "12345678901234567890123", "123456789012345678901234"};
139
        for (String str : strs) {
140
            assertFalse(" string is compact but must not be", CharSequences.isCompact(str));
141
            assertTrue(" string is not compact but must be", CharSequences.isCompact(CharSequences.create(str)));
142
        }
143
        assertTrue(" empty string is not compact ", CharSequences.isCompact(CharSequences.empty()));
144
    }
145
146
    /**
147
     * Test of indexOf method, of class CharSequences.
148
     */
149
    @Test
150
    public void testIndexOf_CharSequence_CharSequence() {
151
        CharSequence text = CharSequences.create("CharSequences");
152
        CharSequence seq = CharSequences.create("Sequence");
153
        assertEquals(4, CharSequences.indexOf(text, "Sequence"));
154
        assertEquals(4, CharSequences.indexOf(text, seq));
155
        assertEquals(4, CharSequences.indexOf("CharSequences", "Sequence"));
156
        assertEquals(4, CharSequences.indexOf("CharSequences", seq));
157
        assertEquals(-1, CharSequences.indexOf(text, "Sequens"));
158
    }
159
160
    /**
161
     * Test of indexOf method, of class CharSequences.
162
     */
163
    @Test
164
    public void testIndexOf_3args() {
165
        CharSequence text = CharSequences.create("CharSequences");
166
        CharSequence seq = CharSequences.create("Sequence");
167
        assertEquals(4, CharSequences.indexOf(text, "Sequence", 2));
168
        assertEquals(4, CharSequences.indexOf(text, seq, 2));
169
        assertEquals(4, CharSequences.indexOf("CharSequences", "Sequence", 2));
170
        assertEquals(4, CharSequences.indexOf("CharSequences", seq, 2));
171
        assertEquals(-1, CharSequences.indexOf("CharSequences", seq, 5));
172
    }
173
174
}

Return to bug 183162