KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > text > TextBuilder


1 /*
2  * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
3  * Copyright (C) 2006 - Javolution (http://javolution.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package javolution.text;
10
11 import j2me.io.Serializable;
12 import j2me.lang.CharSequence;
13 import j2mex.realtime.MemoryArea;
14
15 import javolution.context.Realtime;
16 import javolution.context.RealtimeObject;
17 import javolution.lang.MathLib;
18 import javolution.lang.Reusable;
19
20 /**
21  * <p> This class represents an {@link Appendable} text whose capacity expands
22  * gently without incurring expensive resize/copy operations ever.</p>
23  *
24  * <p> This class is not intended for large documents manipulations which
25  * should be performed with the {@link Text} class directly
26  * (<code>O(Log(n))</code> {@link Text#insert insertion} and
27  * {@link Text#delete deletion} capabilities).</p>
28  *
29  * <p> This implementation is not synchronized.</p>
30  *
31  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
32  * @version 3.7, January 1, 2006
33  */

34 public class TextBuilder extends RealtimeObject implements Appendable JavaDoc,
35         CharSequence JavaDoc, Reusable, Serializable {
36
37     /**
38      * Holds the factory for this text builder.
39      */

40     private static final Factory FACTORY = new Factory() {
41         public Object JavaDoc create() {
42             return new TextBuilder();
43         }
44     };
45
46     //
47
// Holds the character buffers. The array sizes are adjusted to ensures that
48
// no more than 4 time the required space is ever allocated.
49
//
50
// char[1<<D3][1<<D2][1<<D1][1<<D0]
51
// with charAt(i) = char[(i>>R3)&M3][(i>>R2)&M2][(i>>R1)&M1][(i>>R0)&M0]
52
//
53

54     static final int D0 = 5;
55
56     static final int M0 = (1 << D0) - 1;
57
58     static final int C0 = 1 << D0; // capacity chars0
59

60     private static final int D1 = D0 + 2;
61
62     private static final int R1 = D0;
63
64     private static final int M1 = (1 << D1) - 1;
65
66     private static final int C1 = 1 << (D0 + D1); // capacity chars1
67

68     private static final int D2 = D1 + 2;
69
70     private static final int R2 = D0 + D1;
71
72     private static final int M2 = (1 << D2) - 1;
73
74     private static final int C2 = 1 << (D0 + D1 + D2); // capacity chars2
75

76     private static final int D3 = D2 + 2;
77
78     private static final int R3 = D0 + D1 + D2;
79
80     private final char[] _chars0 = new char[1 << D0]; // 5 bits (32).
81

82     private char[][] _chars1; // new char[1<<7][1<<5]; // 12 bits (4096)
83

84     private char[][][] _chars2; // new char[1<<9][1<<7][1<<5]; // 21 bits (2097152)
85

86     private char[][][][] _chars3; // new char[1<<11][1<<9][1<<7][1<<5];
87

88     /**
89      * Holds the current capacity.
90      */

91     private int _capacity = C0;
92
93     /**
94      * Holds the current length.
95      */

96     private int _length;
97
98     /**
99      * Creates a text builder of small initial capacity.
100      */

101     public TextBuilder() {
102     }
103
104     /**
105      * Creates a text builder holding the specified character sequence.
106      *
107      * @param csq the initial character sequence of this text builder.
108      */

109     public TextBuilder(CharSequence JavaDoc csq) {
110         append(csq);
111     }
112
113     /**
114      * Creates a text builder holding the specified <code>String</code>.
115      *
116      * @param str the initial string content of this text builder.
117      */

118     public TextBuilder(String JavaDoc str) {
119         append(str);
120     }
121
122     /**
123      * Creates a text builder of specified initial capacity.
124      * Unless the text length exceeds the specified capacity, operations
125      * on this text builder will not allocate memory.
126      *
127      * @param capacity the initial capacity.
128      */

129     public TextBuilder(int capacity) {
130         while (capacity > _capacity) {
131             increaseCapacity();
132         }
133     }
134
135     /**
136      * Returns a new, preallocated or {@link #recycle recycled} text builder
137      * (on the stack when executing in a {@link javolution.context.PoolContext
138      * PoolContext}).
139      *
140      * @return a new, preallocated or recycled text builder instance.
141      */

142     public static TextBuilder newInstance() {
143         TextBuilder textBuilder = (TextBuilder) FACTORY.object();
144         textBuilder._length = 0;
145         return textBuilder;
146     }
147
148     /**
149      * Recycles a text builder {@link #newInstance() instance} immediately
150      * (on the stack when executing in a {@link javolution.context.PoolContext
151      * PoolContext}).
152      */

153     public static void recycle(TextBuilder instance) {
154         FACTORY.recycle(instance);
155     }
156
157     /**
158      * Returns the length (character count) of this text builder.
159      *
160      * @return the number of characters (16-bits Unicode).
161      */

162     public final int length() {
163         return _length;
164     }
165
166     /**
167      * Returns the character at the specified index.
168      *
169      * @param i the index of the character.
170      * @return the character at the specified index.
171      * @throws IndexOutOfBoundsException if <code>(i < 0) || (i >= this.length())</code>.
172      */

173     public final char charAt(int i) {
174         if ((i < 0) || (i >= _length))
175             throw new IndexOutOfBoundsException JavaDoc();
176         return charsAt(i)[i & M0];
177     }
178     
179     // Returns character block.
180
final char[] charsAt(int i) {
181         return (i < C0) ? _chars0 : (i < C1) ? _chars1[(i >> R1)]
182                 : (i < C2) ? _chars2[(i >> R2)][(i >> R1) & M1]
183                         : _chars3[(i >> R3)][(i >> R2) & M2][(i >> R1) & M1];
184     }
185
186     /**
187      * Copies the character from this text builder into the destination
188      * character array.
189      *
190      * @param srcBegin this text start index.
191      * @param srcEnd this text end index (not included).
192      * @param dst the destination array to copy the data into.
193      * @param dstBegin the offset into the destination array.
194      * @throws IndexOutOfBoundsException if <code>(srcBegin < 0) ||
195      * (dstBegin < 0) || (srcBegin > srcEnd) || (srcEnd > this.length())
196      * || ((dstBegin + srcEnd - srcBegin) > dst.length)</code>
197      */

198     public final void getChars(int srcBegin, int srcEnd, char[] dst,
199             int dstBegin) {
200         if ((srcBegin < 0) || (dstBegin < 0) || (srcBegin > srcEnd)
201                 || (srcEnd > this.length())
202                 || ((dstBegin + srcEnd - srcBegin) > dst.length))
203             throw new IndexOutOfBoundsException JavaDoc();
204         for (int i = srcBegin, j = dstBegin; i < srcEnd;) {
205             char[] chars0 = charsAt(i); // Gets character block.
206
int i0 = i & M0;
207             int length = MathLib.min(C0 - i0, srcEnd - i);
208             System.arraycopy(chars0, i0, dst, j, length);
209             i += length;
210             j += length;
211         }
212     }
213
214     /**
215      * Sets the character at the specified position.
216      *
217      * @param index the index of the character to modify.
218      * @param c the new character.
219      * @throws IndexOutOfBoundsException if <code>(index < 0) ||
220      * (index >= this.length())</code>
221      */

222     public final void setCharAt(int index, char c) {
223         if ((index < 0) || (index >= _length))
224             throw new IndexOutOfBoundsException JavaDoc("index: " + index);
225         charsAt(index)[index & M0] = c;
226     }
227
228     /**
229      * Sets the length of this character builder.
230      * If the length is greater than the current length; the
231      * null character <code>'&#92;u0000'</code> is inserted.
232      *
233      * @param newLength the new length of this builder.
234      * @throws IndexOutOfBoundsException if <code>(newLength < 0)</code>
235      */

236     public final void setLength(int newLength) {
237         if (newLength < 0)
238             throw new IndexOutOfBoundsException JavaDoc();
239         if (newLength <= _length) {
240             _length = newLength;
241         } else {
242             for (int i = _length; i++ < newLength;) {
243                 append('\u0000');
244             }
245         }
246     }
247
248     /**
249      * Returns an instance of {@link Text} (immutable) corresponding
250      * to the character sequence between the specified indexes.
251      *
252      * @param start the index of the first character inclusive.
253      * @param end the index of the last character exclusive.
254      * @return an immutable character sequence.
255      * @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0) ||
256      * (start > end) || (end > this.length())</code>
257      */

258     public final CharSequence JavaDoc subSequence(int start, int end) {
259         if ((start < 0) || (end < 0) || (start > end) || (end > _length))
260             throw new IndexOutOfBoundsException JavaDoc();
261         return Text.valueOf(this, start, end);
262     }
263
264     /**
265      * Appends the specified character.
266      *
267      * @param c the character to append.
268      * @return <code>this</code>
269      */

270     public final Appendable JavaDoc/*TextBuilder*/append(char c) { // Short to be inlined.
271
if (_length >= C0)
272             return append2(c);
273         _chars0[_length++] = c;
274         return this;
275     }
276
277     private Appendable JavaDoc/*TextBuilder*/append2(char c) {
278         if (_length >= _capacity)
279             increaseCapacity();
280         final int i = _length++;
281         if (i < C1) {
282             _chars1[(i >> R1)][i & M0] = c;
283         } else if (i < C2) {
284             _chars2[(i >> R2)][(i >> R1) & M1][i & M0] = c;
285         } else {
286             _chars3[(i >> R3)][(i >> R2) & M2][(i >> R1) & M1][i & M0] = c;
287         }
288         return this;
289     }
290
291     /**
292      * Appends the specified character sequence. If the specified character
293      * sequence is <code>null</code> this method is equivalent to
294      * <code>append("null")</code>.
295      *
296      * @param csq the character sequence to append or <code>null</code>.
297      * @return <code>this</code>
298      */

299     public final Appendable JavaDoc/*TextBuilder*/append(CharSequence JavaDoc csq) {
300         return (csq == null) ? append("null") : append(csq, 0, csq.length());
301     }
302
303     /**
304      * Appends a subsequence of the specified character sequence.
305      * If the specified character sequence is <code>null</code> this method
306      * is equivalent to <code>append("null")</code>.
307      *
308      * @param csq the character sequence to append or <code>null</code>.
309      * @param start the index of the first character to append.
310      * @param end the index after the last character to append.
311      * @return <code>this</code>
312      * @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0)
313      * || (start > end) || (end > csq.length())</code>
314      */

315     public final Appendable JavaDoc/*TextBuilder*/append(CharSequence JavaDoc csq, int start,
316             int end) {
317         if (csq == null)
318             return append("null");
319         if ((start < 0) || (end < 0) || (start > end) || (end > csq.length()))
320             throw new IndexOutOfBoundsException JavaDoc();
321         for (int i = start; i < end;) {
322             append(csq.charAt(i++));
323         }
324         return this;
325     }
326
327     /**
328      * Appends the textual representation of the specified object.
329      * If the specified object is <code>null</code> this method
330      * is equivalent to <code>append("null")</code>.
331      *
332      * @param obj the object to represent or <code>null</code>.
333      * @return <code>this</code>
334      */

335     public final TextBuilder append(Object JavaDoc obj) {
336         if (obj instanceof String JavaDoc) {
337             return append((String JavaDoc) obj);
338         } else if (obj instanceof CharSequence JavaDoc) {
339             return (TextBuilder) append((CharSequence JavaDoc) obj);
340         } else if (obj instanceof Realtime) {
341             return append(((Realtime) obj).toText());
342         } else if (obj != null) {
343             return append(obj.toString());
344         } else {
345             return append("null");
346         }
347     }
348
349     /**
350      * Appends the specified string to this text builder.
351      * If the specified string is <code>null</code> this method
352      * is equivalent to <code>append("null")</code>.
353      *
354      * @param str the string to append or <code>null</code>.
355      * @return <code>this</code>
356      */

357     public final TextBuilder append(String JavaDoc str) {
358         if (str == null)
359             return append("null");
360         final int length = str.length();
361         for (int i = 0; i < length;) {
362             append(str.charAt(i++));
363         }
364         return this;
365     }
366
367     /**
368      * Appends a subsequence of the specified string.
369      * If the specified character sequence is <code>null</code> this method
370      * is equivalent to <code>append("null")</code>.
371      *
372      * @param str the string to append or <code>null</code>.
373      * @param start the index of the first character to append.
374      * @param end the index after the last character to append.
375      * @return <code>this</code>
376      * @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0)
377      * || (start > end) || (end > csq.length())</code>
378      */

379     public final TextBuilder append(String JavaDoc str, int start, int end) {
380         if (str == null)
381             return append("null");
382         if ((start < 0) || (end < 0) || (start > end) || (end > str.length()))
383             throw new IndexOutOfBoundsException JavaDoc();
384         for (int i = start; i < end;) {
385             append(str.charAt(i++));
386         }
387         return this;
388     }
389
390     /**
391      * Appends the specified text to this text builder.
392      * If the specified text is <code>null</code> this method
393      * is equivalent to <code>append("null")</code>.
394      *
395      * @param text the text to append or <code>null</code>.
396      * @return <code>this</code>
397      */

398     public TextBuilder append(Text text) {
399         if (text == null)
400             return append("null");
401         final int length = text.length();
402         for (int i = 0; i < length;) {
403             append(text.charAt(i++));
404         }
405         return this;
406     }
407
408     /**
409      * Appends the characters from the char array argument.
410      *
411      * @param chars the character array source.
412      * @return <code>this</code>
413      */

414     public final TextBuilder append(char chars[]) {
415         return append(chars, 0, chars.length);
416     }
417
418     /**
419      * Appends the characters from a subarray of the char array argument.
420      *
421      * @param chars the character array source.
422      * @param offset the index of the first character to append.
423      * @param length the number of character to append.
424      * @return <code>this</code>
425      * @throws IndexOutOfBoundsException if <code>(offset < 0) ||
426      * (length < 0) || ((offset + length) > chars.length)</code>
427      */

428     public final TextBuilder append(char chars[], int offset, int length) {
429         if ((offset < 0) || (length < 0) || ((offset + length) > chars.length))
430             throw new IndexOutOfBoundsException JavaDoc();
431         final int end = offset + length;
432         for (int i = offset; i < end;) {
433             append(chars[i++]);
434         }
435         return this;
436     }
437
438     /**
439      * Appends the textual representation of the specified <code>boolean</code>
440      * argument.
441      *
442      * @param b the <code>boolean</code> to format.
443      * @return <code>this</code>
444      * @see TypeFormat
445      */

446     public final TextBuilder append(boolean b) {
447         return b ? append("true") : append("false");
448     }
449
450     /**
451      * Appends the decimal representation of the specified <code>int</code>
452      * argument.
453      *
454      * @param i the <code>int</code> to format.
455      * @return <code>this</code>
456      */

457     public final TextBuilder append(int i) {
458         if (i < 0) {
459             if (i == Integer.MIN_VALUE) // Negation would overflow.
460
return append("-2147483648"); // 11 char max.
461
i = -i;
462             append('-');
463         }
464         if (i >= 100000) {
465             int high = i / 100000;
466             writeDigits(high, false);
467             i -= high * 100000;
468             writeDigits(i, true);
469         } else {
470             writeDigits(i, false);
471         }
472         return this;
473     }
474
475     /**
476      * Appends the radix representation of the specified <code>int</code>
477      * argument.
478      *
479      * @param i the <code>int</code> to format.
480      * @param radix the radix (e.g. <code>16</code> for hexadecimal).
481      * @return <code>this</code>
482      */

483     public final TextBuilder append(int i, int radix) {
484         if (radix == 10)
485             return append(i); // Faster version.
486
if (radix < 2 || radix > 36)
487             throw new IllegalArgumentException JavaDoc("radix: " + radix);
488         if (i < 0) {
489             append('-');
490         } else {
491             i = -i;
492         }
493         append2(i, radix);
494         return this;
495     }
496
497     private void append2(int i, int radix) {
498         if (i <= -radix) {
499             append2(i / radix, radix);
500             append(DIGIT_TO_CHAR[-(i % radix)]);
501         } else {
502             append(DIGIT_TO_CHAR[-i]);
503         }
504     }
505
506     /**
507      * Appends the decimal representation of the specified <code>long</code>
508      * argument.
509      *
510      * @param l the <code>long</code> to format.
511      * @return <code>this</code>
512      */

513     public final TextBuilder append(long l) {
514         if (l < 0) {
515             if (l == Long.MIN_VALUE) // Negation would overflow.
516
return append("-9223372036854775808"); // 20 characters max.
517
l = -l;
518             append('-');
519         }
520         boolean writeZero = false;
521         if (l >= 1000000000000000L) {
522             int high = (int) (l / 1000000000000000L);
523             writeDigits(high, writeZero);
524             l -= high * 1000000000000000L;
525             writeZero = true;
526         }
527         if (writeZero || (l >= 10000000000L)) {
528             int high = (int) (l / 10000000000L);
529             writeDigits(high, writeZero);
530             l -= high * 10000000000L;
531             writeZero = true;
532         }
533         if (writeZero || (l >= 100000)) {
534             int high = (int) (l / 100000);
535             writeDigits(high, writeZero);
536             l -= high * 100000L;
537             writeZero = true;
538         }
539         writeDigits((int) l, writeZero);
540         return this;
541     }
542
543     /**
544      * Appends the radix representation of the specified <code>long</code>
545      * argument.
546      *
547      * @param l the <code>long</code> to format.
548      * @param radix the radix (e.g. <code>16</code> for hexadecimal).
549      * @return <code>this</code>
550      */

551     public final TextBuilder append(long l, int radix) {
552         if (radix == 10)
553             return append(l); // Faster version.
554
if (radix < 2 || radix > 36)
555             throw new IllegalArgumentException JavaDoc("radix: " + radix);
556         if (l < 0) {
557             append('-');
558         } else {
559             l = -l;
560         }
561         append2(l, radix);
562         return this;
563     }
564
565     private void append2(long l, int radix) {
566         if (l <= -radix) {
567             append2(l / radix, radix);
568             append(DIGIT_TO_CHAR[(int) -(l % radix)]);
569         } else {
570             append(DIGIT_TO_CHAR[(int) -l]);
571         }
572     }
573
574     /**
575      * Appends the textual representation of the specified <code>float</code>
576      * (equivalent to
577      * <code>append(f, 10, (abs(f) &gt;= 1E7) || (abs(f) &lt; 0.001), false)</code>).
578      *
579      * @param f the <code>float</code> to format.
580      * @return <code>this</code>
581      * @JVM-1.1+@
582      public final TextBuilder append(float f) {
583      return append(f, 10, (MathLib.abs(f) >= 1E7) || (MathLib.abs(f) < 0.001), false);
584      }
585      /**/

586
587     /**
588      * Appends the textual representation of the specified <code>double</code>;
589      * the number of digits is 17 or 16 when the 16 digits representation
590      * can be parsed back to the same <code>double</code> (mimic the standard
591      * library formatting).
592      *
593      * @param d the <code>double</code> to format.
594      * @return <code>append(d, -1, (MathLib.abs(d) >= 1E7) ||
595      * (MathLib.abs(d) < 0.001), false)</code>
596      * @JVM-1.1+@
597      public final TextBuilder append(double d) {
598      return append(d, -1, (MathLib.abs(d) >= 1E7) || (MathLib.abs(d) < 0.001), false);
599      }
600      /**/

601
602     /**
603      * Appends the textual representation of the specified <code>double</code>
604      * according to the specified formatting arguments.
605      *
606      * @param d the <code>double</code> value.
607      * @param digits the number of significative digits (excludes exponent) or
608      * <code>-1</code> to mimic the standard library (16 or 17 digits).
609      * @param scientific <code>true</code> to forces the use of the scientific
610      * notation (e.g. <code>1.23E3</code>); <code>false</code>
611      * otherwise.
612      * @param showZero <code>true</code> if trailing fractional zeros are
613      * represented; <code>false</code> otherwise.
614      * @return <code>this</code>
615      * @throws IllegalArgumentException if <code>(digits &gt; 19)</code>)
616      * @JVM-1.1+@
617      public final TextBuilder append(double d, int digits,
618      boolean scientific, boolean showZero) {
619      if (digits > 19)
620      throw new IllegalArgumentException("digits: " + digits);
621      if (d != d) // NaN
622      return append("NaN");
623      if (d < 0) { // Work with positive number.
624      d = -d;
625      append('-');
626      }
627      if (d == Double.POSITIVE_INFINITY) // Infinity.
628      return append("Infinity");
629      if (d == 0.0) { // Zero.
630      if (digits == 1)
631      return append("0.");
632      if (!showZero)
633      return append("0.0");
634      append("0.0");
635      for (int i = 2; i < digits; i++) {
636      append('0');
637      }
638      return this;
639      }
640      
641      // Find the exponent e such as: value == x.xxx * 10^e
642      int e = MathLib.floorLog10(d);
643      
644      long m;
645      if (digits < 0) { // Use 16 or 17 digits.
646      // Try 17 digits.
647      long m17 = MathLib.toLongPow10(d, (17 - 1) - e);
648      // Check if we can use 16 digits.
649      long m16 = m17 / 10;
650      double dd = MathLib.toDoublePow10(m16, e - 16 + 1);
651      if (dd == d) { // 16 digits is enough.
652      digits = 16;
653      m = m16;
654      } else { // We cannot remove the last digit.
655      digits = 17;
656      m = m17;
657      }
658      } else { // Use the specified number of digits.
659      m = MathLib.toLongPow10(d, (digits - 1) - e);
660      }
661      
662      // Formats.
663      if (scientific || (e >= digits)) {
664      // Scientific notation has to be used ("x.xxxEyy").
665      long pow10 = POW10_LONG[digits - 1];
666      int i = (int) (m / pow10); // Single digit.
667      append(DIGIT_TO_CHAR[i]);
668      m = m - pow10 * i;
669      appendFraction(m, digits - 1, showZero);
670      append('E');
671      append(e);
672      } else { // Dot within the string ("xxxx.xxxxx").
673      if (e < 0) {
674      append('0');
675      } else {
676      long pow10 = POW10_LONG[digits - e - 1];
677      long l = m / pow10;
678      append(l);
679      m = m - pow10 * l;
680      }
681      appendFraction(m, digits - e - 1, showZero);
682      }
683      return this;
684      }
685      private static final long[] POW10_LONG = new long[] { 1L, 10L, 100L, 1000L,
686      10000L, 100000L, 1000000L, 10000000L, 100000000L, 1000000000L,
687      10000000000L, 100000000000L, 1000000000000L, 10000000000000L,
688      100000000000000L, 1000000000000000L, 10000000000000000L,
689      100000000000000000L, 1000000000000000000L };
690      /**/

691
692     final void appendFraction(long l, int digits, boolean showZero) {
693         append('.');
694         int length = MathLib.digitLength(l);
695         if ((length == 0) && !showZero) { // Only one zero shown xxx.0
696
append('0');
697             return;
698         }
699         for (int i = length; i < digits; i++) {
700             append('0');
701         }
702         if (l != 0) {
703             append(l);
704         }
705         if (!showZero) { // Remove trailing zeros.
706
int trailingZeros = 0;
707             while (true) {
708                 char c = charAt(_length - trailingZeros - 1);
709                 if (c != '0')
710                     break;
711                 trailingZeros++;
712             }
713             this.setLength(_length - trailingZeros);
714         }
715     }
716
717     /**
718      * Inserts the specified character sequence at the specified location.
719      *
720      * @param index the insertion position.
721      * @param csq the character sequence being inserted.
722      * @return <code>this</code>
723      * @throws IndexOutOfBoundsException if <code>(index < 0) ||
724      * (index > this.length())</code>
725      */

726     public final TextBuilder insert(int index, CharSequence JavaDoc csq) {
727         if ((index < 0) || (index > _length))
728             throw new IndexOutOfBoundsException JavaDoc("index: " + index);
729         final int shift = csq.length();
730         _length += shift;
731         while (_length >= _capacity) {
732             increaseCapacity();
733         }
734         for (int i = _length - shift; --i >= index;) {
735             this.setCharAt(i + shift, this.charAt(i));
736         }
737         for (int i = csq.length(); --i >= 0;) {
738             this.setCharAt(index + i, csq.charAt(i));
739         }
740         return this;
741     }
742
743     /**
744      * Removes all the characters of this text builder
745      * (equivalent to <code>this.delete(start, this.length())</code>).
746      *
747      * @return <code>this.delete(0, this.length())</code>
748      */

749     public final TextBuilder clear() {
750         _length = 0;
751         return this;
752     }
753
754     /**
755      * Removes the characters between the specified indices.
756      *
757      * @param start the beginning index, inclusive.
758      * @param end the ending index, exclusive.
759      * @return <code>this</code>
760      * @throws IndexOutOfBoundsException if <code>(start < 0) || (end < 0)
761      * || (start > end) || (end > this.length())</code>
762      */

763     public final TextBuilder delete(int start, int end) {
764         if ((start < 0) || (end < 0) || (start > end) || (end > this.length()))
765             throw new IndexOutOfBoundsException JavaDoc();
766         for (int i = end, j = start; i < _length;) {
767             this.setCharAt(j++, this.charAt(i++));
768         }
769         _length -= end - start;
770         return this;
771     }
772
773     /**
774      * Reverses this character sequence.
775      *
776      * @return <code>this</code>
777      */

778     public final TextBuilder reverse() {
779         final int n = _length - 1;
780         for (int j = (n - 1) >> 1; j >= 0;) {
781             char c = charAt(j);
782             setCharAt(j, charAt(n - j));
783             setCharAt(n - j--, c);
784         }
785         return this;
786     }
787
788     /**
789      * Returns the {@link Text} corresponding to this {@link TextBuilder}
790      * (allocated on the "stack" when executing in a
791      * {@link javolution.context.PoolContext PoolContext}).
792      *
793      * @return the corresponding {@link Text} instance.
794      */

795     public final Text toText() {
796         return Text.valueOf(this, 0, _length);
797     }
798
799     /**
800      * Returns the <code>String</code> value holds by this {@link TextBuilder}.
801      *
802      * @return the <code>java.lang.String</code> for this text builder.
803      */

804     public final String JavaDoc stringValue() {
805         char[] data = new char[_length];
806         this.getChars(0, _length, data, 0);
807         return new String JavaDoc(data, 0, _length);
808     }
809
810     /**
811      * Resets this text builder for reuse (equivalent to {@link #clear}).
812      */

813     public final void reset() {
814         _length = 0;
815     }
816
817     /**
818      * Returns the hash code for this text builder.
819      *
820      * @return the hash code value.
821      */

822     public final int hashCode() {
823         int h = 0;
824         for (int i = 0; i < _length;) {
825             h = 31 * h + charAt(i++);
826         }
827         return h;
828     }
829
830     /**
831      * Compares this text builder against the specified object for equality.
832      * Returns <code>true</code> if the specified object is a text builder
833      * having the same character content.
834      *
835      * @param obj the object to compare with or <code>null</code>.
836      * @return <code>true</code> if that is a text builder with the same
837      * character content as this text; <code>false</code> otherwise.
838      */

839     public final boolean equals(Object JavaDoc obj) {
840         if (this == obj)
841             return true;
842         if (!(obj instanceof TextBuilder))
843             return false;
844         TextBuilder that = (TextBuilder) obj;
845         if (this._length != that._length)
846             return false;
847         for (int i = 0; i < _length;) {
848             if (this.charAt(i) != that.charAt(i++))
849                 return false;
850         }
851         return true;
852     }
853
854     /**
855      * Appends the content of this text builder to the specified
856      * string buffer (only for text builder with length less than 32).
857      *
858      * @param sb the string buffer.
859      */

860     final void appendTo(StringBuffer JavaDoc sb) {
861         sb.append(_chars0, 0, _length);
862     }
863
864     /**
865      * Appends the content of this text builder to the specified
866      * string buffer (only for text builder with length less than 32).
867      *
868      * @param sb the string builder.
869      * @JVM-1.5+@
870      final void appendTo(StringBuilder sb) {
871      sb.append(_chars0, 0, _length);
872      }
873      /**/

874
875     /**
876      * Indicates if this text builder has the same character content as the
877      * specified character sequence.
878      *
879      * @param csq the character sequence to compare with.
880      * @return <code>true</code> if the specified character sequence has the
881      * same character content as this text; <code>false</code> otherwise.
882      */

883     public final boolean contentEquals(CharSequence JavaDoc csq) {
884         if (csq.length() != _length)
885             return false;
886         char[] chars = charsAt(0); // Gets character block.
887
for (int i = 0; i < _length;) {
888             if (chars[i & M0] != csq.charAt(i++))
889                 return false;
890             if ((i & M0) == 0) { // Changes character block.
891
chars = charsAt(i);
892             }
893         }
894         return true;
895     }
896
897     /**
898      * Equivalent to {@link #contentEquals(CharSequence)}
899      * (for J2ME compability).
900      *
901      * @param csq the string character sequence to compare with.
902      * @return <code>true</code> if the specified string has the
903      * same character content as this text; <code>false</code> otherwise.
904      */

905     public final boolean contentEquals(String JavaDoc csq) {
906         if (csq.length() != _length)
907             return false;
908         char[] chars = charsAt(0); // Gets character block.
909
for (int i = 0; i < _length;) {
910             if (chars[i & M0] != csq.charAt(i++))
911                 return false;
912             if ((i & M0) == 0) { // Changes character block.
913
chars = charsAt(i);
914             }
915         }
916         return true;
917     }
918
919     /**
920      * Increases this text builder capacity.
921      */

922     private void increaseCapacity() {
923         MemoryArea.getMemoryArea(this).executeInArea(new Runnable JavaDoc() {
924             public void run() {
925                 final int c = _capacity;
926                 _capacity += 1 << D0;
927                 if (c < C1) {
928                     if (_chars1 == null) {
929                         _chars1 = new char[1 << D1][];
930                     }
931                     _chars1[(c >> R1)] = new char[1 << D0];
932
933                 } else if (c < C2) {
934                     if (_chars2 == null) {
935                         _chars2 = new char[1 << D2][][];
936                     }
937                     if (_chars2[(c >> R2)] == null) {
938                         _chars2[(c >> R2)] = new char[1 << D1][];
939                     }
940                     _chars2[(c >> R2)][(c >> R1) & M1] = new char[1 << D0];
941
942                 } else {
943                     if (_chars3 == null) {
944                         _chars3 = new char[1 << D3][][][];
945                     }
946                     if (_chars3[(c >> R3)] == null) {
947                         _chars3[(c >> R3)] = new char[1 << D2][][];
948                     }
949                     if (_chars3[(c >> R3)][(c >> R2) & M2] == null) {
950                         _chars3[(c >> R3)][(c >> R2) & M2] = new char[1 << D1][];
951                     }
952                     _chars3[(c >> R3)][(c >> R2) & M2][(c >> R1) & M1] = new char[1 << D0];
953                 }
954             }
955         });
956     }
957
958     /**
959      * Appends the specified positive integer [0 .. 99999] in decimal
960      * representation to this text builder.
961      *
962      * @param i the integer to write.
963      * @param writeZero <code>true</code> if leading zero are included;
964      * <code>false</code> otherwise.
965      */

966     private void writeDigits(int i, boolean writeZero) {
967         {
968             final int e = 10000;
969             if (i >= e) {
970                 writeZero = true;
971                 if (i >= e * 5) {
972                     if (i >= e * 8) {
973                         if (i >= e * 9) {
974                             append('9');
975                             i -= e * 9;
976                         } else {
977                             append('8');
978                             i -= e * 8;
979                         }
980                     } else { // [5 .. 8[
981
if (i >= e * 7) {
982                             append('7');
983                             i -= e * 7;
984                         } else if (i >= e * 6) {
985                             append('6');
986                             i -= e * 6;
987                         } else {
988                             append('5');
989                             i -= e * 5;
990                         }
991                     }
992                 } else { // [1 ..5[
993
if (i >= e * 3) {
994                         if (i >= e * 4) {
995                             append('4');
996                             i -= e * 4;
997                         } else {
998                             append('3');
999                             i -= e * 3;
1000                        }
1001                    } else { // [1 .. 2[
1002
if (i >= e * 2) {
1003                            append('2');
1004                            i -= e * 2;
1005                        } else {
1006                            append('1');
1007                            i -= e;
1008                        }
1009                    }
1010                }
1011            } else if (writeZero) {
1012                append('0');
1013            }
1014        }
1015        {
1016            final int e = 1000;
1017            if (i >= e) {
1018                writeZero = true;
1019                if (i >= e * 5) {
1020                    if (i >= e * 8) {
1021                        if (i >= e * 9) {
1022                            append('9');
1023                            i -= e * 9;
1024                        } else {
1025                            append('8');
1026                            i -= e * 8;
1027                        }
1028                    } else { // [5 .. 8[
1029
if (i >= e * 7) {
1030                            append('7');
1031                            i -= e * 7;
1032                        } else if (i >= e * 6) {
1033                            append('6');
1034                            i -= e * 6;
1035                        } else {
1036                            append('5');
1037                            i -= e * 5;
1038                        }
1039                    }
1040                } else { // [1 ..5[
1041
if (i >= e * 3) {
1042                        if (i >= e * 4) {
1043                            append('4');
1044                            i -= e * 4;
1045                        } else {
1046                            append('3');
1047                            i -= e * 3;
1048                        }
1049                    } else { // [1 .. 2[
1050
if (i >= e * 2) {
1051                            append('2');
1052                            i -= e * 2;
1053                        } else {
1054                            append('1');
1055                            i -= e;
1056                        }
1057                    }
1058                }
1059            } else if (writeZero) {
1060                append('0');
1061            }
1062        }
1063        {
1064            final int e = 100;
1065            if (i >= e) {
1066                writeZero = true;
1067                if (i >= e * 5) {
1068                    if (i >= e * 8) {
1069                        if (i >= e * 9) {
1070                            append('9');
1071                            i -= e * 9;
1072                        } else {
1073                            append('8');
1074                            i -= e * 8;
1075                        }
1076                    } else { // [5 .. 8[
1077
if (i >= e * 7) {
1078                            append('7');
1079                            i -= e * 7;
1080                        } else if (i >= e * 6) {
1081                            append('6');
1082                            i -= e * 6;
1083                        } else {
1084                            append('5');
1085                            i -= e * 5;
1086                        }
1087                    }
1088                } else { // [1 ..5[
1089
if (i >= e * 3) {
1090                        if (i >= e * 4) {
1091                            append('4');
1092                            i -= e * 4;
1093                        } else {
1094                            append('3');
1095                            i -= e * 3;
1096                        }
1097                    } else { // [1 .. 2[
1098
if (i >= e * 2) {
1099                            append('2');
1100                            i -= e * 2;
1101                        } else {
1102                            append('1');
1103                            i -= e;
1104                        }
1105                    }
1106                }
1107            } else if (writeZero) {
1108                append('0');
1109            }
1110        }
1111        {
1112            final int e = 10;
1113            if (i >= e) {
1114                writeZero = true;
1115                if (i >= e * 5) {
1116                    if (i >= e * 8) {
1117                        if (i >= e * 9) {
1118                            append('9');
1119                            i -= e * 9;
1120                        } else {
1121                            append('8');
1122                            i -= e * 8;
1123                        }
1124                    } else { // [5 .. 8[
1125
if (i >= e * 7) {
1126                            append('7');
1127                            i -= e * 7;
1128                        } else if (i >= e * 6) {
1129                            append('6');
1130                            i -= e * 6;
1131                        } else {
1132                            append('5');
1133                            i -= e * 5;
1134                        }
1135                    }
1136                } else { // [1 ..5[
1137
if (i >= e * 3) {
1138                        if (i >= e * 4) {
1139                            append('4');
1140                            i -= e * 4;
1141                        } else {
1142                            append('3');
1143                            i -= e * 3;
1144                        }
1145                    } else { // [1 .. 2[
1146
if (i >= e * 2) {
1147                            append('2');
1148                            i -= e * 2;
1149                        } else {
1150                            append('1');
1151                            i -= e;
1152                        }
1153                    }
1154                }
1155            } else if (writeZero) {
1156                append('0');
1157            }
1158        }
1159        append(DIGIT_TO_CHAR[i]);
1160    }
1161
1162    /**
1163     * Holds the digits to character mapping.
1164     */

1165    private final static char[] DIGIT_TO_CHAR = { '0', '1', '2', '3', '4', '5',
1166            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
1167            'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
1168            'w', 'x', 'y', 'z' };
1169
1170}
Popular Tags