001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.util;
030:
031: import java.io.InputStream;
032:
033: /**
034: * CharBuffer is an unsynchronized version of StringBuffer.
035: */
036: public final class CharBuffer extends CharSegment {
037: private static final int MIN_CAPACITY = 64;
038:
039: /**
040: * Constructs a char buffer with no characters.
041: */
042: public CharBuffer() {
043: _buffer = new char[MIN_CAPACITY];
044: _length = 0;
045: }
046:
047: /**
048: * Constructs a char buffer with the given initial capacity
049: *
050: * @param capacity initial capacity
051: */
052: public CharBuffer(int capacity) {
053: if (capacity < 0)
054: throw new IllegalArgumentException();
055: if (capacity < MIN_CAPACITY)
056: capacity = MIN_CAPACITY;
057:
058: _buffer = new char[capacity];
059: _length = 0;
060: }
061:
062: /**
063: * Constructs a char buffer with the given initial string
064: *
065: * @param string initial string
066: */
067: public CharBuffer(String string) {
068: int length = string.length();
069: int capacity = length + MIN_CAPACITY;
070:
071: _buffer = new char[capacity];
072: _length = length;
073: string.getChars(0, length, _buffer, 0);
074: }
075:
076: /**
077: * Constructs a char buffer with the given initial string
078: *
079: * @param string initial string
080: */
081: public CharBuffer(String string, int offset, int length) {
082: int capacity = length;
083: if (capacity < MIN_CAPACITY)
084: capacity = MIN_CAPACITY;
085:
086: _buffer = new char[capacity];
087: _length = length;
088: string.getChars(offset, length, _buffer, 0);
089: }
090:
091: public static CharBuffer allocate() {
092: return new CharBuffer();
093: }
094:
095: public void free() {
096: }
097:
098: /**
099: * Returns the character count of the buffer's contents.
100: */
101: public int length() {
102: return _length;
103: }
104:
105: /**
106: * Returns the buffer length
107: */
108: public int getLength() {
109: return _length;
110: }
111:
112: /**
113: * Returns the capacity of the buffer, i.e. how many chars it
114: * can hold.
115: */
116: public int capacity() {
117: return _buffer.length;
118: }
119:
120: public int getCapacity() {
121: return _buffer.length;
122: }
123:
124: /**
125: * Ensure the buffer can hold at least 'minimumCapacity' chars.
126: */
127: public final void ensureCapacity(int minimumCapacity) {
128: if (minimumCapacity <= _buffer.length) {
129: return;
130: }
131:
132: expandCapacity(minimumCapacity);
133: }
134:
135: /**
136: * Expands the capacity to a new value.
137: */
138: private final void expandCapacity(int minimumCapacity) {
139: int oldCapacity = _buffer.length;
140: int newCapacity = oldCapacity * 2;
141:
142: if (newCapacity < 0)
143: newCapacity = Integer.MAX_VALUE;
144: else if (newCapacity < minimumCapacity)
145: newCapacity = minimumCapacity;
146:
147: char[] chars = new char[newCapacity];
148:
149: System.arraycopy(_buffer, 0, chars, 0, oldCapacity);
150:
151: _buffer = chars;
152: }
153:
154: /**
155: * Clears the buffer. Equivalent to setLength(0)
156: */
157: public final void clear() {
158: _length = 0;
159: }
160:
161: /**
162: * Set the length of the buffer.
163: */
164: public final void setLength(int newLength) {
165: if (newLength < 0)
166: throw new IndexOutOfBoundsException("illegal argument");
167: else if (_buffer.length < newLength)
168: expandCapacity(newLength);
169:
170: _length = newLength;
171: }
172:
173: /**
174: * Returns the char at the specified offset.
175: */
176: public char charAt(int i) {
177: if (i < 0 || _length <= i)
178: throw new IndexOutOfBoundsException();
179:
180: return _buffer[i];
181: }
182:
183: /**
184: * Returns the last character of the buffer
185: *
186: * @throws IndexOutOfBoundsException for an empty buffer
187: */
188: public char getLastChar() {
189: if (_length == 0)
190: throw new IndexOutOfBoundsException();
191:
192: return _buffer[_length - 1];
193: }
194:
195: /**
196: * Returns the buffer's char array.
197: */
198: public final char[] getBuffer() {
199: return _buffer;
200: }
201:
202: /**
203: * Copies characters to the destination buffer.
204: */
205: public void getChars(int srcBegin, int srcEnd, char[] dst,
206: int dstBegin) {
207: char[] buffer = _buffer;
208: while (srcBegin < srcEnd)
209: dst[dstBegin++] = buffer[srcBegin++];
210: }
211:
212: /**
213: * Sets the character at the given index.
214: */
215: public void setCharAt(int index, char ch) {
216: if (index < 0 || _length <= index)
217: throw new IndexOutOfBoundsException();
218:
219: _buffer[index] = ch;
220: }
221:
222: /**
223: * Appends the string representation of the object to the buffer.
224: */
225: public CharBuffer append(Object obj) {
226: return append(String.valueOf(obj));
227: }
228:
229: /**
230: * Appends the string representation of the object to the buffer.
231: */
232: public CharBuffer append(CharBuffer cb) {
233: return append(cb._buffer, 0, cb._length);
234: }
235:
236: /**
237: * Appends the string.
238: */
239: public CharBuffer append(String string) {
240: if (string == null)
241: string = "null";
242:
243: int len = string.length();
244: int newLength = _length + len;
245: int length = _length;
246: if (_buffer.length <= newLength)
247: expandCapacity(newLength);
248:
249: string.getChars(0, len, _buffer, length);
250:
251: _length = newLength;
252:
253: return this ;
254: }
255:
256: public CharBuffer append(String string, int offset, int len) {
257: if (_buffer.length <= len + _length)
258: expandCapacity(len + _length);
259:
260: string.getChars(offset, offset + len, _buffer, _length);
261:
262: _length += len;
263:
264: return this ;
265: }
266:
267: /**
268: * Appends the characters to the buffer.
269: */
270: public CharBuffer append(char[] buffer) {
271: return append(buffer, 0, buffer.length);
272: }
273:
274: /**
275: * Appends the characters to the buffer.
276: */
277: public CharBuffer append(char[] buffer, int offset, int length) {
278: if (_buffer.length < _length + length)
279: expandCapacity(_length + length);
280:
281: System.arraycopy(buffer, offset, _buffer, _length, length);
282:
283: _length += length;
284:
285: return this ;
286: }
287:
288: /**
289: * Appends the boolean representation to the buffer
290: */
291: public final CharBuffer append(boolean b) {
292: return append(String.valueOf(b));
293: }
294:
295: /**
296: * Appends the character to the buffer
297: */
298: public final CharBuffer append(char ch) {
299: if (_buffer.length <= _length)
300: expandCapacity(_length + 1);
301:
302: _buffer[_length++] = ch;
303:
304: return this ;
305: }
306:
307: /**
308: * Add an int to the buffer.
309: */
310: public CharBuffer append(int i) {
311: if (i == 0x80000000) {
312: return append("-2147483648");
313: }
314:
315: int length = _length;
316:
317: if (_buffer.length <= length + 16)
318: expandCapacity(length + 16);
319:
320: char[] buffer = _buffer;
321:
322: if (i < 0) {
323: buffer[length++] = '-';
324: i = -i;
325: } else if (i == 0) {
326: buffer[_length++] = '0';
327: return this ;
328: }
329:
330: int start = length;
331: while (i > 0) {
332: buffer[length++] = (char) ((i % 10) + '0');
333: i /= 10;
334: }
335:
336: for (int j = (length - start) / 2; j > 0; j--) {
337: char temp = buffer[length - j];
338: buffer[length - j] = buffer[start + j - 1];
339: buffer[start + j - 1] = temp;
340: }
341:
342: _length = length;
343:
344: return this ;
345: }
346:
347: /**
348: * Add a long to the buffer.
349: */
350: public CharBuffer append(long i) {
351: if (i == 0x8000000000000000L) {
352: return append("-9223372036854775808");
353: }
354:
355: int length = _length;
356:
357: if (_buffer.length < length + 32)
358: expandCapacity(length + 32);
359:
360: char[] buffer = _buffer;
361:
362: if (i < 0) {
363: buffer[length++] = '-';
364: i = -i;
365: } else if (i == 0) {
366: buffer[_length++] = '0';
367: return this ;
368: }
369:
370: int start = length;
371: while (i > 0) {
372: buffer[length++] = (char) ((i % 10) + '0');
373: i /= 10;
374: }
375:
376: for (int j = (length - start) / 2; j > 0; j--) {
377: char temp = buffer[length - j];
378: buffer[length - j] = buffer[start + j - 1];
379: buffer[start + j - 1] = temp;
380: }
381:
382: _length = length;
383:
384: return this ;
385: }
386:
387: /**
388: * Add a float to the buffer.
389: */
390: public CharBuffer append(float f) {
391: return append(String.valueOf(f));
392: }
393:
394: /**
395: * Add a double to the buffer.
396: */
397: public CharBuffer append(double d) {
398: return append(String.valueOf(d));
399: }
400:
401: /**
402: * Appends iso-8859-1 bytes to the buffer
403: */
404: public final CharBuffer append(byte[] buf, int offset, int len) {
405: int length = _length;
406: if (_buffer.length < _length + len)
407: expandCapacity(_length + len);
408:
409: char[] buffer = _buffer;
410: for (; len > 0; len--)
411: buffer[length++] = (char) buf[offset++];
412:
413: _length = length;
414:
415: return this ;
416: }
417:
418: /**
419: * Deletes characters from the buffer.
420: */
421: public CharBuffer delete(int start, int end) {
422: if (start < 0 || end < start || _length < start)
423: throw new StringIndexOutOfBoundsException();
424:
425: if (_length < end)
426: end = _length;
427:
428: int tail = _length - end;
429: char[] buffer = _buffer;
430:
431: for (int i = 0; i < tail; i++)
432: buffer[start + i] = buffer[end + i];
433:
434: _length -= end - start;
435:
436: return this ;
437: }
438:
439: /**
440: * Deletes a character from the buffer.
441: */
442: public CharBuffer deleteCharAt(int index) {
443: if (index < 0 || _length < index)
444: throw new StringIndexOutOfBoundsException();
445:
446: if (index == _length)
447: return this ;
448:
449: int tail = _length - index + 1;
450: char[] buffer = _buffer;
451:
452: for (int i = 0; i < tail; i++)
453: buffer[index + i] = buffer[index + i + 1];
454:
455: _length--;
456:
457: return this ;
458: }
459:
460: /**
461: * Replaces a range with a string
462: */
463: public CharBuffer replace(int start, int end, String string) {
464: if (start < 0 || end < start || _length < start)
465: throw new StringIndexOutOfBoundsException();
466:
467: int len = string.length();
468: int length = _length;
469:
470: if (_buffer.length < len + length - (end - start))
471: expandCapacity(len + length - (end - start));
472:
473: char[] buffer = _buffer;
474:
475: if (len < end - start) {
476: int tail = length - end;
477: for (int i = 0; i < tail; i++)
478: buffer[start + len + i] = buffer[end + i];
479: } else {
480: int tail = length - end;
481: for (int i = tail - 1; i >= 0; i--)
482: buffer[end + i] = buffer[start + len + i];
483: }
484:
485: string.getChars(0, len, buffer, start);
486:
487: _length = length + len - (end - start);
488:
489: return this ;
490: }
491:
492: /**
493: * Replaces a range with a character array
494: */
495: public CharBuffer replace(int start, int end, char[] buffer,
496: int offset, int len) {
497: if (start < 0 || end < start || _length < start)
498: throw new StringIndexOutOfBoundsException();
499:
500: if (_buffer.length < len + _length - (end - start))
501: expandCapacity(len + _length - (end - start));
502:
503: char[] this Buffer = _buffer;
504:
505: if (len < end - start) {
506: int tail = _length - end;
507: for (int i = 0; i < tail; i++)
508: this Buffer[start + len + i] = this Buffer[end + i];
509: } else {
510: int tail = _length - end;
511: for (int i = tail - 1; i >= 0; i--)
512: this Buffer[end + i] = this Buffer[start + len + i];
513: }
514:
515: System.arraycopy(buffer, offset, this Buffer, start, len);
516:
517: _length += len - (end - start);
518:
519: return this ;
520: }
521:
522: /**
523: * Returns a substring
524: */
525: public String substring(int start) {
526: if (_length < start || start < 0)
527: throw new StringIndexOutOfBoundsException();
528:
529: return new String(_buffer, start, _length - start);
530: }
531:
532: /**
533: * Returns a substring
534: */
535: public String substring(int start, int end) {
536: if (_length < start || start < 0 || end < start)
537: throw new StringIndexOutOfBoundsException();
538:
539: return new String(_buffer, start, end - start);
540: }
541:
542: /**
543: * Inserts a string.
544: */
545: public CharBuffer insert(int index, String string) {
546: if (string == null)
547: string = "null";
548:
549: if (index < 0 || _length < index)
550: throw new StringIndexOutOfBoundsException();
551:
552: int len = string.length();
553:
554: if (_buffer.length < _length + len)
555: expandCapacity(len + _length);
556:
557: int tail = _length - index;
558: char[] buffer = _buffer;
559:
560: for (int i = tail - 1; i >= 0; i--)
561: buffer[index + len + i] = buffer[index + i];
562:
563: string.getChars(0, len, buffer, index);
564: _length += len;
565:
566: return this ;
567: }
568:
569: /**
570: * Inserts a character buffer.
571: */
572: public CharBuffer insert(int index, char[] buffer, int offset,
573: int len) {
574: if (index < 0 || _length < index)
575: throw new StringIndexOutOfBoundsException();
576:
577: if (_buffer.length < len + _length)
578: expandCapacity(len + _length);
579:
580: int tail = _length - index;
581: char[] this Buffer = _buffer;
582: for (int i = tail - 1; i >= 0; i--)
583: buffer[index + len + i] = this Buffer[index + i];
584:
585: System.arraycopy(buffer, offset, this Buffer, index, len);
586: _length += len;
587:
588: return this ;
589: }
590:
591: /**
592: * Inserts an object at a given offset.
593: */
594: public CharBuffer insert(int offset, Object o) {
595: return insert(offset, String.valueOf(o));
596: }
597:
598: /**
599: * Inserts a character at a given offset.
600: */
601: public CharBuffer insert(int offset, char ch) {
602: return insert(offset, String.valueOf(ch));
603: }
604:
605: /**
606: * Inserts an integer at a given offset.
607: */
608: public CharBuffer insert(int offset, int i) {
609: return insert(offset, String.valueOf(i));
610: }
611:
612: /**
613: * Inserts a long at a given offset.
614: */
615: public CharBuffer insert(int offset, long l) {
616: return insert(offset, String.valueOf(l));
617: }
618:
619: /**
620: * Inserts a float at a given offset.
621: */
622: public CharBuffer insert(int offset, float f) {
623: return insert(offset, String.valueOf(f));
624: }
625:
626: /**
627: * Inserts a double at a given offset.
628: */
629: public CharBuffer insert(int offset, double d) {
630: return insert(offset, String.valueOf(d));
631: }
632:
633: public int indexOf(char ch) {
634: return indexOf(ch, 0);
635: }
636:
637: /**
638: * Clones the buffer
639: */
640: public Object clone() {
641: CharBuffer newBuffer = new CharBuffer();
642:
643: newBuffer.setLength(_length);
644:
645: System.arraycopy(_buffer, 0, newBuffer._buffer, 0, _length);
646:
647: return newBuffer;
648: }
649:
650: /**
651: * String representation of the buffer.
652: */
653: public String toString() {
654: return new String(_buffer, 0, _length);
655: }
656:
657: public String close() {
658: String string = new String(_buffer, 0, _length);
659: free();
660: return string;
661: }
662:
663: class CBInputStream extends InputStream {
664: int _index = 0;
665:
666: public int read() {
667: if (_length <= _index)
668: return -1;
669:
670: return _buffer[_index++];
671: }
672: }
673:
674: public InputStream getInputStream() {
675: return new CBInputStream();
676: }
677: }
|