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/apichanges.xml (+16 lines)
Lines 48-53 Link Here
48
    <apidef name="actions">Actions API</apidef>
48
    <apidef name="actions">Actions API</apidef>
49
</apidefs>
49
</apidefs>
50
<changes>
50
<changes>
51
    <change id="CharSequences">
52
        <api name="util"/>
53
        <summary>Added <code>CharSequences</code></summary>
54
        <version major="8" minor="3"/>
55
        <date day="31" month="03" year="2010"/>
56
        <author login="vv159170"/>
57
        <compatibility addition="yes"/>
58
        <description>
59
            <p>
60
                <code>CharSequences.create</code> now can be used
61
                to create memory efficient implementations of CharSequences for ASCII strings.
62
            </p>
63
        </description>
64
        <class package="org.openide.util" name="CharSequences"/>
65
        <issue number="183162"/>
66
    </change>
51
    <change id="ActionInvoker-ActionPresenterProvider">
67
    <change id="ActionInvoker-ActionPresenterProvider">
52
        <api name="actions"/>
68
        <api name="actions"/>
53
        <summary>Action SPI interfaces added</summary>
69
        <summary>Action SPI interfaces added</summary>
(-)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 (+959 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
 * 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
}
(-)a/openide.util/test/unit/src/org/openide/util/CharSequencesTest.java (+220 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 junit.framework.AssertionFailedError;
45
import org.junit.Test;
46
47
/**
48
 *
49
 * @author Vladimir Voskresensky
50
 */
51
public class CharSequencesTest extends NbTestCase {
52
53
    public CharSequencesTest() {
54
        super("CharSequencesTest");
55
    }
56
57
    /**
58
     * Test of create method, of class CharSequences.
59
     */
60
    @Test
61
    public void testCreate_3args() {
62
        char[] buf = new char[] {'H', 'e', 'l', 'l', 'o', ',', ' ', 'P', 'l', 'a', 't', 'f', 'o', 'r', 'm', '!'};
63
        for (int start = 0; start < buf.length; start++) {
64
            for (int count = 1; count < buf.length - start; count++) {
65
                CharSequence expResult = new String(buf, start, count);
66
                CharSequence result = CharSequences.create(buf, start, count);
67
                assertEquals("["+start+", " + count+"]", expResult, result.toString());
68
            }
69
        }
70
    }
71
72
    /**
73
     * Test of create method, of class CharSequences.
74
     */
75
    @Test
76
    public void testCreate_CharSequence() {
77
        String[] strs = new String[] { "", "1234567", "123456789012345", "12345678901234567890123", "123456789012345678901234" };
78
        for (String str : strs) {
79
            assertEquals(str, CharSequences.create(str).toString());
80
            assertEquals(CharSequences.create(str).toString(), str);
81
            assertEquals(CharSequences.create(str).toString(), CharSequences.create(str).toString());
82
        }
83
    }
84
85
    /**
86
     * Test of comparator method, of class CharSequences.
87
     */
88
    @Test
89
    public void testCaseSensitiveComparator() {
90
        Comparator<CharSequence> comparator = CharSequences.comparator(false);
91
        String[] strs = new String[]{"", "1234567", "123456789012345", "12345678901234567890123", "123456789012345678901234"};
92
        for (String str : strs) {
93
            assertEquals(0, comparator.compare(str, CharSequences.create(str)));
94
            assertEquals(0, comparator.compare(CharSequences.create(str), str));
95
            assertEquals(0, comparator.compare(CharSequences.create(str), CharSequences.create(str)));
96
        }
97
    }
98
99
    /**
100
     * Test of comparator method, of class CharSequences.
101
     */
102
    @Test
103
    public void testCaseInsensitiveComparator() {
104
        Comparator<CharSequence> comparator = CharSequences.comparator(true);
105
        String[] strs = new String[]{"", "1234567", "123456789012345", "12345678901234567890123", "123456789012345678901234"};
106
        for (int i = 0; i < strs.length; i++) {
107
            String str = strs[i];
108
            String upperStr = str.toUpperCase();
109
            String lowerStr = str.toLowerCase();
110
            assertEquals(0, comparator.compare(str, CharSequences.create(str)));
111
            assertEquals(0, comparator.compare(CharSequences.create(str), str));
112
            assertEquals(0, comparator.compare(CharSequences.create(str), CharSequences.create(str)));
113
            assertEquals(0, comparator.compare(upperStr, CharSequences.create(str)));
114
            assertEquals(0, comparator.compare(CharSequences.create(str), upperStr));
115
            assertEquals(0, comparator.compare(CharSequences.create(upperStr), CharSequences.create(str)));
116
            assertEquals(0, comparator.compare(lowerStr, CharSequences.create(str)));
117
            assertEquals(0, comparator.compare(CharSequences.create(str), lowerStr));
118
            assertEquals(0, comparator.compare(CharSequences.create(str), CharSequences.create(lowerStr)));
119
        }
120
    }
121
122
    /**
123
     * Test of empty method, of class CharSequences.
124
     */
125
    @Test
126
    public void testEmpty() {
127
        assertEquals("", CharSequences.create("").toString());
128
        assertEquals(CharSequences.create("").toString(), "");
129
        assertEquals("", CharSequences.empty().toString());
130
        assertEquals(CharSequences.empty().toString(), "");
131
        assertSame(CharSequences.empty(), CharSequences.create(""));
132
    }
133
134
    /**
135
     * Test of isCompact method, of class CharSequences.
136
     */
137
    @Test
138
    public void testIsCompact() {
139
        String[] strs = new String[]{"", "1234567", "123456789012345", "12345678901234567890123", "123456789012345678901234"};
140
        for (String str : strs) {
141
            assertFalse(" string is compact but must not be", CharSequences.isCompact(str));
142
            assertTrue(" string is not compact but must be", CharSequences.isCompact(CharSequences.create(str)));
143
        }
144
        assertTrue(" empty string is not compact ", CharSequences.isCompact(CharSequences.empty()));
145
    }
146
147
    /**
148
     * Test of indexOf method, of class CharSequences.
149
     */
150
    @Test
151
    public void testIndexOf_CharSequence_CharSequence() {
152
        CharSequence text = CharSequences.create("CharSequences");
153
        CharSequence seq = CharSequences.create("Sequence");
154
        assertEquals(4, CharSequences.indexOf(text, "Sequence"));
155
        assertEquals(4, CharSequences.indexOf(text, seq));
156
        assertEquals(4, CharSequences.indexOf("CharSequences", "Sequence"));
157
        assertEquals(4, CharSequences.indexOf("CharSequences", seq));
158
        assertEquals(-1, CharSequences.indexOf(text, "Sequens"));
159
    }
160
161
    /**
162
     * Test of indexOf method, of class CharSequences.
163
     */
164
    @Test
165
    public void testIndexOf_3args() {
166
        CharSequence text = CharSequences.create("CharSequences");
167
        CharSequence seq = CharSequences.create("Sequence");
168
        assertEquals(4, CharSequences.indexOf(text, "Sequence", 2));
169
        assertEquals(4, CharSequences.indexOf(text, seq, 2));
170
        assertEquals(4, CharSequences.indexOf("CharSequences", "Sequence", 2));
171
        assertEquals(4, CharSequences.indexOf("CharSequences", seq, 2));
172
        assertEquals(-1, CharSequences.indexOf("CharSequences", seq, 5));
173
    }
174
175
    @Test
176
    public void testSizes() {
177
        // 32-bit JVM
178
        //String    String CharSequence
179
        //Length     Size    Size
180
        //1..2        40      16
181
        //3..6        48      16
182
        //7..7        56      16
183
        //8..10       56      24
184
        //11..14      64      24
185
        //15..15      72      24
186
        //16..18      72      32
187
        //19..22      80      32
188
        //23..23      88      32
189
        //24..26      88      56
190
        //27..28      96      56
191
        //29..30      96      64
192
        //31..34     104      64
193
        //35..36     112      64
194
        //37..38     112      72
195
        //39..42     120      72
196
        //......................
197
        //79..82   - 200     112
198
        char[] buf = "12345678901234567890123456789012345678901234567890".toCharArray();
199
        int curStrLen = 0;
200
        int[][] lenSize = new int[][] { { 7, 16 }, { 15, 24 }, { 23, 32 }, {28, 56 }, { 36, 64 }, {42, 72} };
201
        for (int j = 0; j < lenSize.length; j++) {
202
            int strLenLimit = lenSize[j][0];
203
            int sizeLimit = lenSize[j][1];
204
            for (; curStrLen <= strLenLimit; curStrLen++) {
205
                CharSequence cs = CharSequences.create(buf, 0, curStrLen);
206
                assertSize("Size is too big " + cs, sizeLimit, cs);
207
                // check we are better than strings
208
                boolean stringIsBigger = false;
209
                String str = new String(buf, 0, curStrLen);
210
                try {
211
                    assertSize("Size is too big for " + str, sizeLimit, str);
212
                } catch (AssertionFailedError e) {
213
//                    System.err.println(e.getMessage());
214
                    stringIsBigger = true;
215
                }
216
                assertTrue("string object is smaller than our char sequence", stringIsBigger);
217
            }
218
        }
219
    }
220
}

Return to bug 183162