KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jcorporate > expresso > kernel > util > FastStringBuffer


1 /* ====================================================================
2  * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
3  *
4  * Copyright (c) 1995-2003 Jcorporate Ltd. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * 3. The end-user documentation included with the redistribution,
19  * if any, must include the following acknowledgment:
20  * "This product includes software developed by Jcorporate Ltd.
21  * (http://www.jcorporate.com/)."
22  * Alternately, this acknowledgment may appear in the software itself,
23  * if and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. "Jcorporate" and product names such as "Expresso" must
26  * not be used to endorse or promote products derived from this
27  * software without prior written permission. For written permission,
28  * please contact info@jcorporate.com.
29  *
30  * 5. Products derived from this software may not be called "Expresso",
31  * or other Jcorporate product names; nor may "Expresso" or other
32  * Jcorporate product names appear in their name, without prior
33  * written permission of Jcorporate Ltd.
34  *
35  * 6. No product derived from this software may compete in the same
36  * market space, i.e. framework, without prior written permission
37  * of Jcorporate Ltd. For written permission, please contact
38  * partners@jcorporate.com.
39  *
40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
41  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43  * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
44  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
46  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
47  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
48  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * ====================================================================
53  *
54  * This software consists of voluntary contributions made by many
55  * individuals on behalf of the Jcorporate Ltd. Contributions back
56  * to the project(s) are encouraged when you make modifications.
57  * Please send them to support@jcorporate.com. For more information
58  * on Jcorporate Ltd. and its products, please see
59  * <http://www.jcorporate.com/>.
60  *
61  * Portions of this software are based upon other open source
62  * products and are subject to their respective licenses.
63  */

64
65 package com.jcorporate.expresso.kernel.util;
66
67 import org.apache.commons.pool.BasePoolableObjectFactory;
68 import org.apache.commons.pool.ObjectPool;
69 import org.apache.commons.pool.impl.StackObjectPool;
70
71 /**
72  * <p>A fast string buffer implements a mutable sequence of characters.
73  * </p>
74  * <p>Fast string buffers are unsafe for use by multiple threads.
75  * </p>
76  * <p>Every string buffer has a capacity. As long as the length of the
77  * character sequence contained in the string buffer does not exceed
78  * the capacity, it is not necessary to allocate a new internal
79  * buffer array. If the internal buffer overflows, it is
80  * automatically made larger.</p>
81  * <p>There are several performance improvements that make it worthwhile to
82  * use this class over the standard JDK <code>StringBuffer</code>
83  * <ul>
84  * <li>Method calls are unsynchronized. Calls to synchronized methods are
85  * automatically at least four times slower than unsynchronized methods</li>
86  * <li>Pooling. By using the pooling mechanism, you basically remove all
87  * string allocation overhead and the fast string buffer is most likely
88  * pre-allocated to a size you'll use</li>
89  * <li>Non-zeroing out. <code>StringBuffer</code> zero's out it's character array,
90  * even though it's not necessary. FastStringBuffer doesn't perform any memory
91  * zeroing<li>
92  * <li>Parameter Checks removed. FastStringBuffer doesn't perform any out of bounds
93  * checks against incoming strings and parameters. This automatically saves overhead
94  * at the expense of you potentially getting less descriptive error messages</li>
95  * <li>Reuse. By calling the <code>clear()</code> method you can reuse a FastStringBuffer
96  * thus saving yourself a lot of memory allocations</li>
97  * </ul>
98  *
99  * @see java.io.ByteArrayOutputStream
100  * @see java.lang.StringBuffer
101  * @since Expresso 4.0, Pooling Mechanism since Expreso 5.0
102  */

103 public final class FastStringBuffer
104         implements java.io.Serializable JavaDoc {
105
106     /**
107      * The value is used for character storage.
108      */

109     private char[] value;
110
111     /**
112      * The count is the number of characters in the buffer.
113      */

114     private int count;
115
116     /**
117      * A flag indicating whether the buffer is shared
118      */

119     private boolean shared;
120
121     static FastStringBuffer pointerInstance = null;
122
123     /**
124      * Pointer to the object factory. [Which is a inner class]
125      */

126     private static FastStringBufferObjectFactory factory = null;
127
128
129     /**
130      * The Apache Commons Object Pool
131      */

132     private static ObjectPool thePool = null;
133
134
135
136     /** use serialVersionUID from JDK 1.0.2 for interoperability */
137     // static final long serialVersionUID = 3388685877147921107L;
138
/**
139      * Constructs a string buffer with no characters in it and an
140      * initial capacity of 16 characters.
141      */

142     public FastStringBuffer() {
143         this(16);
144     }
145
146     /**
147      * Constructs a string buffer with no characters in it and an
148      * initial capacity specified by the <code>length</code> argument.
149      *
150      * @param length the initial capacity.
151      * @throws NegativeArraySizeException if the <code>length</code>
152      * argument is less than <code>0</code>.
153      */

154     public FastStringBuffer(int length) {
155         synchronized (FastStringBuffer.class) {
156             if (factory == null) {
157                 factory = new FastStringBuffer.FastStringBufferObjectFactory();
158             }
159         }
160         value = new char[length];
161         shared = false;
162     }
163
164     /**
165      * Constructs a string buffer so that it represents the same
166      * sequence of characters as the string argument. The initial
167      * capacity of the string buffer is <code>16</code> plus the length
168      * of the string argument.
169      *
170      * @param str the initial contents of the buffer.
171      */

172     public FastStringBuffer(String JavaDoc str) {
173         this(str.length() + 16);
174         append(str);
175
176         synchronized (FastStringBuffer.class) {
177             if (factory == null) {
178                 factory = new FastStringBuffer.FastStringBufferObjectFactory();
179             }
180         }
181
182     }
183
184     /**
185      * Returns the length (character count) of this string buffer.
186      *
187      * @return the number of characters in this string buffer.
188      */

189     public int length() {
190         return count;
191     }
192
193     /**
194      * Returns the current capacity of the String buffer. The capacity
195      * is the amount of storage available for newly inserted
196      * characters; beyond which an allocation will occur.
197      *
198      * @return the current capacity of this string buffer.
199      */

200     public int capacity() {
201         return value.length;
202     }
203
204     /**
205      * Clears the buffer and prepares it for reuse.
206      */

207     public void clear() {
208         copyWhenShared();
209         count = 0;
210     }
211
212     /**
213      * Copies the buffer value if it is shared.
214      */

215     private final void copyWhenShared() {
216         if (shared) {
217             char[] newValue = new char[value.length];
218             System.arraycopy(value, 0, newValue, 0, count);
219             value = newValue;
220             shared = false;
221         }
222     }
223
224     /**
225      * Ensures that the capacity of the buffer is at least equal to the
226      * specified minimum.
227      * If the current capacity of this string buffer is less than the
228      * argument, then a new internal buffer is allocated with greater
229      * capacity. The new capacity is the larger of:
230      * <ul>
231      * <li>The <code>minimumCapacity</code> argument.
232      * <li>Twice the old capacity, plus <code>2</code>.
233      * </ul>
234      * If the <code>minimumCapacity</code> argument is nonpositive, this
235      * method takes no action and simply returns.
236      *
237      * @param minimumCapacity the minimum desired capacity.
238      */

239     public void ensureCapacity(int minimumCapacity) {
240         int maxCapacity = value.length;
241
242         if (minimumCapacity > maxCapacity) {
243             int newCapacity = maxCapacity + maxCapacity + 2;
244
245             if (minimumCapacity > newCapacity) {
246                 newCapacity = minimumCapacity;
247             }
248
249             char[] newValue = new char[newCapacity];
250             System.arraycopy(value, 0, newValue, 0, count);
251             value = newValue;
252             shared = false;
253         }
254     }
255
256     /**
257      * Sets the length of this String buffer.
258      * If the <code>newLength</code> argument is less than the current
259      * length of the string buffer, the string buffer is truncated to
260      * contain exactly the number of characters given by the
261      * <code>newLength</code> argument.
262      * <p/>
263      * If the <code>newLength</code> argument is greater than or equal
264      * to the current length, sufficient null characters
265      * (<code>'&#92;u0000'</code>) are appended to the string buffer so that
266      * length becomes the <code>newLength</code> argument.
267      * <p/>
268      * The <code>newLength</code> argument must be greater than or equal
269      * to <code>0</code>.
270      *
271      * @param newLength the new length of the buffer.
272      * @see java.lang.StringBuffer#length()
273      */

274     public void setLength(int newLength) {
275         ensureCapacity(newLength);
276
277         if (count < newLength) {
278             copyWhenShared();
279
280 // for (; count < newLength; count++) {
281
// value[count] = '\0';
282
// }
283
}
284
285         count = newLength;
286     }
287
288     /**
289      * Returns the character at a specific index in this string buffer.
290      * <p/>
291      * The first character of a string buffer is at index
292      * <code>0</code>, the next at index <code>1</code>, and so on, for
293      * array indexing.
294      * <p/>
295      * The index argument must be greater than or equal to
296      * <code>0</code>, and less than the length of this string buffer.
297      *
298      * @param index the index of the desired character.
299      * @return the character at the specified index of this string buffer.
300      * @see java.lang.StringBuffer#length()
301      */

302     public char charAt(int index) {
303         return value[index];
304     }
305
306     /**
307      * Characters are copied from this string buffer into the
308      * destination character array <code>dst</code>. The first character to
309      * be copied is at index <code>srcBegin</code>; the last character to
310      * be copied is at index <code>srcEnd-1.</code> The total number of
311      * characters to be copied is <code>srcEnd-srcBegin</code>. The
312      * characters are copied into the subarray of <code>dst</code> starting
313      * at index <code>dstBegin</code> and ending at index:
314      * <p><blockquote><pre>
315      * dstbegin + (srcEnd-srcBegin) - 1
316      * </pre></blockquote>
317      *
318      * @param srcBegin start copying at this offset in the string buffer.
319      * @param srcEnd stop copying at this offset in the string buffer.
320      * @param dst the array to copy the data into.
321      * @param dstBegin offset into <code>dst</code>.
322      * @throws StringIndexOutOfBoundsException
323      * if there is an invalid
324      * index into the buffer.
325      */

326     public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) {
327         System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd -
328                 srcBegin);
329     }
330
331     /**
332      * The character at the specified index of this string buffer is set
333      * to <code>ch</code>.
334      * <p/>
335      * The offset argument must be greater than or equal to
336      * <code>0</code>, and less than the length of this string buffer.
337      *
338      * @param index the index of the character to modify.
339      * @param ch the new character.
340      * @throws StringIndexOutOfBoundsException
341      * if the index is invalid.
342      * @see java.lang.StringBuffer#length()
343      */

344     public void setCharAt(int index, char ch) {
345         copyWhenShared();
346         value[index] = ch;
347     }
348
349     /**
350      * Appends the string representation of the <code>Object</code>
351      * argument to this string buffer.
352      * <p/>
353      * The argument is converted to a string as if by the method
354      * <code>String.valueOf</code>, and the characters of that
355      * string are then appended to this string buffer.
356      *
357      * @param obj an <code>Object</code>.
358      * @return this string buffer.
359      * @see java.lang.String#valueOf(java.lang.Object)
360      * @see java.lang.StringBuffer#append(java.lang.String)
361      */

362     public FastStringBuffer append(Object JavaDoc obj) {
363         return append(String.valueOf(obj));
364     }
365
366     /**
367      * Appends the string to this string buffer.
368      * <p/>
369      * The characters of the <code>String</code> argument are appended, in
370      * order, to the contents of this string buffer, increasing the
371      * length of this string buffer by the length of the argument.
372      *
373      * @param str a string.
374      * @return this string buffer.
375      */

376     public FastStringBuffer append(String JavaDoc str) {
377         if (str == null) {
378             str = String.valueOf(str);
379         }
380
381         int len = str.length();
382         ensureCapacity(count + len);
383         copyWhenShared();
384         str.getChars(0, len, value, count);
385         count += len;
386
387         return this;
388     }
389
390     /**
391      * Appends the string representation of the <code>char</code> array
392      * argument to this string buffer.
393      * <p/>
394      * The characters of the array argument are appended, in order, to
395      * the contents of this string buffer. The length of this string
396      * buffer increases by the length of the argument.
397      *
398      * @param str the characters to be appended.
399      * @return this string buffer.
400      */

401     public FastStringBuffer append(char[] str) {
402         int len = str.length;
403         ensureCapacity(count + len);
404         copyWhenShared();
405         System.arraycopy(str, 0, value, count, len);
406         count += len;
407
408         return this;
409     }
410
411     /**
412      * Appends the string representation of a subarray of the
413      * <code>char</code> array argument to this string buffer.
414      * <p/>
415      * Characters of the character array <code>str</code>, starting at
416      * index <code>offset</code>, are appended, in order, to the contents
417      * of this string buffer. The length of this string buffer increases
418      * by the value of <code>len</code>.
419      *
420      * @param str the characters to be appended.
421      * @param offset the index of the first character to append.
422      * @param len the number of characters to append.
423      * @return this string buffer.
424      */

425     public FastStringBuffer append(char[] str, int offset, int len) {
426         ensureCapacity(count + len);
427         copyWhenShared();
428         System.arraycopy(str, offset, value, count, len);
429         count += len;
430
431         return this;
432     }
433
434     /**
435      * Appends one FastStringBuffer to another so they can be merged with no
436      * unnecessary allocations
437      *
438      * @param str The string buffer to append to.
439      * @return this string buffer
440      */

441     public FastStringBuffer append(FastStringBuffer str) {
442         int len = str.length();
443         ensureCapacity(count + str.count);
444         copyWhenShared();
445         System.arraycopy(str.getValue(), 0, value, count, len);
446         count += len;
447
448         return this;
449     }
450
451     /**
452      * Appends the string representation of the <code>boolean</code>
453      * argument to the string buffer.
454      * <p/>
455      * The argument is converted to a string as if by the method
456      * <code>String.valueOf</code>, and the characters of that
457      * string are then appended to this string buffer.
458      *
459      * @param b a <code>boolean</code>.
460      * @return this string buffer.
461      * @see java.lang.String#valueOf(boolean)
462      * @see java.lang.StringBuffer#append(java.lang.String)
463      */

464     public FastStringBuffer append(boolean b) {
465         return append(String.valueOf(b));
466     }
467
468     /**
469      * Appends the string representation of the <code>char</code>
470      * argument to this string buffer.
471      * <p/>
472      * The argument is appended to the contents of this string buffer.
473      * The length of this string buffer increases by <code>1</code>.
474      *
475      * @param c a <code>char</code>.
476      * @return this string buffer.
477      */

478     public FastStringBuffer append(char c) {
479         ensureCapacity(count + 1);
480         copyWhenShared();
481         value[count++] = c;
482
483         return this;
484     }
485
486     /**
487      * Appends the string representation of the <code>int</code>
488      * argument to this string buffer.
489      * <p/>
490      * The argument is converted to a string as if by the method
491      * <code>String.valueOf</code>, and the characters of that
492      * string are then appended to this string buffer.
493      *
494      * @param i an <code>int</code>.
495      * @return this string buffer.
496      * @see java.lang.String#valueOf(int)
497      * @see java.lang.StringBuffer#append(java.lang.String)
498      */

499     public FastStringBuffer append(int i) {
500         return append(String.valueOf(i));
501     }
502
503     /**
504      * Appends the string representation of the <code>long</code>
505      * argument to this string buffer.
506      * <p/>
507      * The argument is converted to a string as if by the method
508      * <code>String.valueOf</code>, and the characters of that
509      * string are then appended to this string buffer.
510      *
511      * @param l a <code>long</code>.
512      * @return this string buffer.
513      * @see java.lang.String#valueOf(long)
514      * @see java.lang.StringBuffer#append(java.lang.String)
515      */

516     public FastStringBuffer append(long l) {
517         return append(String.valueOf(l));
518     }
519
520     /**
521      * Appends the string representation of the <code>float</code>
522      * argument to this string buffer.
523      * <p/>
524      * The argument is converted to a string as if by the method
525      * <code>String.valueOf</code>, and the characters of that
526      * string are then appended to this string buffer.
527      *
528      * @param f a <code>float</code>.
529      * @return this string buffer.
530      * @see java.lang.String#valueOf(float)
531      * @see java.lang.StringBuffer#append(java.lang.String)
532      */

533     public FastStringBuffer append(float f) {
534         return append(String.valueOf(f));
535     }
536
537     /**
538      * Appends the string representation of the <code>double</code>
539      * argument to this string buffer.
540      * <p/>
541      * The argument is converted to a string as if by the method
542      * <code>String.valueOf</code>, and the characters of that
543      * string are then appended to this string buffer.
544      *
545      * @param d a <code>double</code>.
546      * @return this string buffer.
547      * @see java.lang.String#valueOf(double)
548      * @see java.lang.StringBuffer#append(java.lang.String)
549      */

550     public FastStringBuffer append(double d) {
551         return append(String.valueOf(d));
552     }
553
554     /**
555      * The character sequence contained in this string buffer is
556      * replaced by the reverse of the sequence.
557      *
558      * @return this string buffer.
559      */

560     public FastStringBuffer reverse() {
561         copyWhenShared();
562
563         int n = count - 1;
564
565         for (int j = (n - 1) >> 1; j >= 0; --j) {
566             char temp = value[j];
567             value[j] = value[n - j];
568             value[n - j] = temp;
569         }
570
571         return this;
572     }
573
574     /**
575      * Converts to a string representing the data in this string buffer.
576      * A new <code>String</code> object is allocated and initialized to
577      * contain the character sequence currently represented by this
578      * string buffer. This <code>String</code> is then returned. Subsequent
579      * changes to the string buffer do not affect the contents of the
580      * <code>String</code>.
581      *
582      * @return a string representation of the string buffer.
583      */

584     public String JavaDoc toString() {
585         return new String JavaDoc(value, 0, count);
586     }
587
588     //
589
// The following two methods are needed by String to efficiently
590
// convert a StringBuffer into a String. They are not public.
591
// They shouldn't be called by anyone but String.
592
final void setShared() {
593         shared = true;
594     }
595
596     final char[] getValue() {
597         return value;
598     }
599
600
601     /**
602      * Retrieve an instance of FastString buffer from the object pool. The object
603      * is often preallocated to a 1024 byte size from a pool of objects. This
604      * can drastically reduce small memory allocations and increate performance.
605      *
606      * @return an instantiaged FastStringBuffer instance.
607      */

608     public synchronized static FastStringBuffer getInstance() {
609         synchronized (FastStringBuffer.class) {
610             if (FastStringBuffer.pointerInstance == null) {
611                 pointerInstance = new FastStringBuffer(1);
612                 thePool = new StackObjectPool(factory);
613             }
614
615             try {
616                 return (FastStringBuffer) thePool.borrowObject();
617
618             } catch (Exception JavaDoc ex) {
619                 System.err.println(ex.getMessage());
620                 ex.printStackTrace();
621                 return null;
622             }
623         }
624     }
625
626     /**
627      * Sends the FastStringBuffer back to the object pool. Use this if you have
628      * obtained the FastStringBuffer instance through FastStringBuffer.getInstance()
629      */

630     public void release() {
631         synchronized (FastStringBuffer.class) {
632             try {
633                 thePool.returnObject(this);
634             } catch (Exception JavaDoc ex) {
635             }
636         }
637     }
638
639
640     /**
641      * An implementation of a PoolableObject factory to work with FastStringBuffers.
642      * Preallocates 1024-char buffers and downsizes them if over than when passivated.
643      *
644      * @author Michael Rimov
645      */

646     class FastStringBufferObjectFactory extends BasePoolableObjectFactory {
647         // for makeObject we'll simply return a new buffer
648
public Object JavaDoc makeObject() {
649             return new FastStringBuffer(1024);
650         }
651
652         //we'll clear it out and reset it's size to 1024 if it grew
653
//bigger than one k.
654
public void passivateObject(Object JavaDoc obj) {
655             FastStringBuffer buf = (FastStringBuffer) obj;
656             if (buf.value.length > 1024) {
657                 buf.value = new char[1024];
658                 buf.clear();
659             } else {
660                 buf.clear();
661             }
662         }
663
664         // for all other methods, the no-op
665
// implementation in BasePoolableObjectFactory
666
// will suffice
667

668     }
669 }
Popular Tags