001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.nio;
019:
020: import java.io.IOException;
021:
022: /**
023: * A buffer of <code>char</code>s.
024: * <p>
025: * A char buffer can be created in either of the following ways:
026: * <ul>
027: * <li>{@link #allocate(int) Allocate} a new char array and create a buffer
028: * based on it;</li>
029: * <li>{@link #wrap(char[]) Wrap} an existing char array to create a new
030: * buffer;</li>
031: * <li>{@link #wrap(CharSequence) Wrap} an existing char sequence to create a
032: * new buffer;</li>
033: * <li>Use {@link java.nio.ByteBuffer#asCharBuffer() ByteBuffer.asCharBuffer}
034: * to create a char buffer based on a byte buffer.</li>
035: * </ul>
036: * </p>
037: *
038: */
039: public abstract class CharBuffer extends Buffer implements
040: Comparable<CharBuffer>, CharSequence, Appendable, Readable {
041:
042: /**
043: * Creates a char buffer based on a new allocated char array.
044: *
045: * @param capacity
046: * The capacity of the new buffer
047: * @return The created char buffer
048: * @throws IllegalArgumentException
049: * If <code>capacity</code> is less than zero
050: */
051: public static CharBuffer allocate(int capacity) {
052: if (capacity < 0) {
053: throw new IllegalArgumentException();
054: }
055: return BufferFactory.newCharBuffer(capacity);
056: }
057:
058: /**
059: * Creates a new char buffer by wrapping the given char array.
060: * <p>
061: * Calling this method has the same effect as
062: * <code>wrap(array, 0, array.length)</code>.
063: * </p>
064: *
065: * @param array
066: * The char array which the new buffer will be based on
067: * @return The created char buffer
068: */
069: public static CharBuffer wrap(char[] array) {
070: return wrap(array, 0, array.length);
071: }
072:
073: /**
074: * Creates new a char buffer by wrapping the given char array.
075: * <p>
076: * The new buffer's position will be <code>start</code>, limit will be
077: * <code>start + len</code>, capacity will be the length of the array.
078: * </p>
079: *
080: * @param array
081: * The char array which the new buffer will be based on
082: * @param start
083: * The start index, must be no less than zero and no greater than
084: * <code>array.length</code>
085: * @param len
086: * The length, must be no less than zero and no greater than
087: * <code>array.length - start</code>
088: * @return The created char buffer
089: * @exception IndexOutOfBoundsException
090: * If either <code>start</code> or <code>len</code> is
091: * invalid
092: */
093: public static CharBuffer wrap(char[] array, int start, int len) {
094: int length = array.length;
095: if ((start < 0) || (len < 0)
096: || (long) start + (long) len > length) {
097: throw new IndexOutOfBoundsException();
098: }
099:
100: CharBuffer buf = BufferFactory.newCharBuffer(array);
101: buf.position = start;
102: buf.limit = start + len;
103:
104: return buf;
105: }
106:
107: /**
108: * Creates a new char buffer by wrapping the given char sequence.
109: * <p>
110: * Calling this method has the same effect as
111: * <code>wrap(chseq, 0, chseq.length())</code>.
112: * </p>
113: *
114: * @param chseq
115: * The char sequence which the new buffer will be based on
116: * @return The created char buffer
117: */
118: public static CharBuffer wrap(CharSequence chseq) {
119: return BufferFactory.newCharBuffer(chseq);
120: }
121:
122: /**
123: * Creates a new char buffer by wrapping the given char sequence.
124: * <p>
125: * The new buffer's position will be <code>start</code>, limit will be
126: * <code>end</code>, capacity will be the length of the char sequence.
127: * The new buffer is readonly.
128: * </p>
129: *
130: * @param chseq
131: * The char sequence which the new buffer will be based on
132: * @param start
133: * The start index, must be no less than zero and no greater than
134: * <code>chseq.length()</code>
135: * @param end
136: * The end index, must be no less than <code>start</code> and
137: * no greater than <code>chseq.length()</code>
138: * @return The created char buffer
139: * @exception IndexOutOfBoundsException
140: * If either <code>start</code> or <code>end</code> is
141: * invalid
142: */
143: public static CharBuffer wrap(CharSequence chseq, int start, int end) {
144: if (chseq == null) {
145: throw new NullPointerException();
146: }
147: if (start < 0 || end < start || end > chseq.length()) {
148: throw new IndexOutOfBoundsException();
149: }
150:
151: CharBuffer result = BufferFactory.newCharBuffer(chseq);
152: result.position = start;
153: result.limit = end;
154: return result;
155: }
156:
157: /**
158: * Constructs a <code>CharBuffer</code> with given capacity.
159: *
160: * @param capacity
161: * The capacity of the buffer
162: */
163: CharBuffer(int capacity) {
164: super (capacity);
165: }
166:
167: /**
168: * Returns the char array which this buffer is based on, if there's one.
169: *
170: * @return The char array which this buffer is based on
171: * @exception ReadOnlyBufferException
172: * If this buffer is based on an array, but it is readonly
173: * @exception UnsupportedOperationException
174: * If this buffer is not based on an array
175: */
176: public final char[] array() {
177: return protectedArray();
178: }
179:
180: /**
181: * Returns the offset of the char array which this buffer is based on, if
182: * there's one.
183: * <p>
184: * The offset is the index of the array corresponds to the zero position of
185: * the buffer.
186: * </p>
187: *
188: * @return The offset of the char array which this buffer is based on
189: * @exception ReadOnlyBufferException
190: * If this buffer is based on an array, but it is readonly
191: * @exception UnsupportedOperationException
192: * If this buffer is not based on an array
193: */
194: public final int arrayOffset() {
195: return protectedArrayOffset();
196: }
197:
198: /**
199: * Returns a readonly buffer that shares content with this buffer.
200: * <p>
201: * The returned buffer is guaranteed to be a new instance, even this buffer
202: * is readonly itself. The new buffer's position, limit, capacity and mark
203: * are the same as this buffer.
204: * </p>
205: * <p>
206: * The new buffer shares content with this buffer, which means this buffer's
207: * change of content will be visible to the new buffer. The two buffer's
208: * position, limit and mark are independent.
209: * </p>
210: *
211: * @return A readonly version of this buffer.
212: */
213: public abstract CharBuffer asReadOnlyBuffer();
214:
215: /**
216: * Returns the character located at the specified index in the buffer. The
217: * index value is referenced from the current buffer position.
218: *
219: * @param index
220: * The index referenced from the current buffer position. It must
221: * not be less than zero but less than the value obtained from a
222: * call to <code>remaining()</code>
223: * @return the character located at the specified index (referenced from the
224: * current position) in the buffer.
225: * @exception IndexOutOfBoundsException
226: * If the index is invalid
227: */
228: public final char charAt(int index) {
229: if (index < 0 || index >= remaining()) {
230: throw new IndexOutOfBoundsException();
231: }
232: return get(position + index);
233: }
234:
235: /**
236: * Compacts this char buffer.
237: * <p>
238: * The remaining <code>char</code>s will be moved to the head of the
239: * buffer, staring from position zero. Then the position is set to
240: * <code>remaining()</code>; the limit is set to capacity; the mark is
241: * cleared.
242: * </p>
243: *
244: * @return This buffer
245: * @exception ReadOnlyBufferException
246: * If no changes may be made to the contents of this buffer
247: */
248: public abstract CharBuffer compact();
249:
250: /**
251: * Compare the remaining <code>char</code>s of this buffer to another
252: * char buffer's remaining <code>char</code>s.
253: *
254: * @param otherBuffer
255: * Another char buffer
256: * @return a negative value if this is less than <code>other</code>; 0 if
257: * this equals to <code>other</code>; a positive value if this is
258: * greater than <code>other</code>
259: * @exception ClassCastException
260: * If <code>other</code> is not a char buffer
261: */
262: public int compareTo(CharBuffer otherBuffer) {
263: int compareRemaining = (remaining() < otherBuffer.remaining()) ? remaining()
264: : otherBuffer.remaining();
265: int this Pos = position;
266: int otherPos = otherBuffer.position;
267: char this Byte, otherByte;
268: while (compareRemaining > 0) {
269: this Byte = get(this Pos);
270: otherByte = otherBuffer.get(otherPos);
271: if (this Byte != otherByte) {
272: return this Byte < otherByte ? -1 : 1;
273: }
274: this Pos++;
275: otherPos++;
276: compareRemaining--;
277: }
278: return remaining() - otherBuffer.remaining();
279: }
280:
281: /**
282: * Returns a duplicated buffer that shares content with this buffer.
283: * <p>
284: * The duplicated buffer's position, limit, capacity and mark are the same
285: * as this buffer. The duplicated buffer's readonly property and byte order
286: * are same as this buffer too.
287: * </p>
288: * <p>
289: * The new buffer shares content with this buffer, which means either
290: * buffer's change of content will be visible to the other. The two buffer's
291: * position, limit and mark are independent.
292: * </p>
293: *
294: * @return A duplicated buffer that shares content with this buffer.
295: */
296: public abstract CharBuffer duplicate();
297:
298: /**
299: * Tests whether this char buffer equals to another object.
300: * <p>
301: * If <code>other</code> is not a char buffer, then false is returned.
302: * </p>
303: * <p>
304: * Two char buffers are equals if, and only if, their remaining
305: * <code>char</code>s are exactly the same. Position, limit, capacity and
306: * mark are not considered.
307: * </p>
308: *
309: * @param other
310: * the object to be compared against
311: * @return Whether this char buffer equals to another object.
312: */
313: @Override
314: public boolean equals(Object other) {
315: if (!(other instanceof CharBuffer)) {
316: return false;
317: }
318: CharBuffer otherBuffer = (CharBuffer) other;
319:
320: if (remaining() != otherBuffer.remaining()) {
321: return false;
322: }
323:
324: int myPosition = position;
325: int otherPosition = otherBuffer.position;
326: boolean equalSoFar = true;
327: while (equalSoFar && (myPosition < limit)) {
328: equalSoFar = get(myPosition++) == otherBuffer
329: .get(otherPosition++);
330: }
331:
332: return equalSoFar;
333: }
334:
335: /**
336: * Returns the char at the current position and increase the position by 1.
337: *
338: * @return The char at the current position.
339: * @exception BufferUnderflowException
340: * If the position is equal or greater than limit
341: */
342: public abstract char get();
343:
344: /**
345: * Reads <code>char</code>s from the current position into the specified
346: * char array and increase the position by the number of <code>char</code>s
347: * read.
348: * <p>
349: * Calling this method has the same effect as
350: * <code>get(dest, 0, dest.length)</code>.
351: * </p>
352: *
353: * @param dest
354: * The destination char array
355: * @return This buffer
356: * @exception BufferUnderflowException
357: * if <code>dest.length</code> is greater than
358: * <code>remaining()</code>
359: */
360: public CharBuffer get(char[] dest) {
361: return get(dest, 0, dest.length);
362: }
363:
364: /**
365: * Reads <code>char</code>s from the current position into the specified
366: * char array, starting from the specified offset, and increase the position
367: * by the number of <code>char</code>s read.
368: *
369: * @param dest
370: * The target char array
371: * @param off
372: * The offset of the char array, must be no less than zero and no
373: * greater than <code>dest.length</code>
374: * @param len
375: * The number of <code>char</code>s to read, must be no less
376: * than zero and no greater than <code>dest.length - off</code>
377: * @return This buffer
378: * @exception IndexOutOfBoundsException
379: * If either <code>off</code> or <code>len</code> is
380: * invalid
381: * @exception BufferUnderflowException
382: * If <code>len</code> is greater than
383: * <code>remaining()</code>
384: */
385: public CharBuffer get(char[] dest, int off, int len) {
386: int length = dest.length;
387: if ((off < 0) || (len < 0) || (long) off + (long) len > length) {
388: throw new IndexOutOfBoundsException();
389: }
390:
391: if (len > remaining()) {
392: throw new BufferUnderflowException();
393: }
394: for (int i = off; i < off + len; i++) {
395: dest[i] = get();
396: }
397: return this ;
398: }
399:
400: /**
401: * Returns a char at the specified index, and the position is not changed.
402: *
403: * @param index
404: * The index, must be no less than zero and less than limit
405: * @return A char at the specified index.
406: * @exception IndexOutOfBoundsException
407: * If index is invalid
408: */
409: public abstract char get(int index);
410:
411: /**
412: * Returns whether this buffer is based on a char array and is read/write.
413: * <p>
414: * If this buffer is readonly, then false is returned.
415: * </p>
416: *
417: * @return Whether this buffer is based on a char array and is read/write.
418: */
419: public final boolean hasArray() {
420: return protectedHasArray();
421: }
422:
423: /**
424: * Hash code is calculated from the remaining <code>char</code>s.
425: * <p>
426: * Position, limit, capacity and mark don't affect the hash code.
427: * </p>
428: *
429: * @return The hash code calculated from the remaining <code>char</code>s.
430: */
431: @Override
432: public int hashCode() {
433: int myPosition = position;
434: int hash = 0;
435: while (myPosition < limit) {
436: hash = hash + get(myPosition++);
437: }
438: return hash;
439: }
440:
441: /**
442: * Returns true if this buffer is direct.
443: * <p>
444: * A direct buffer will try its best to take advantage of native memory APIs
445: * and it may not stay in java heap, thus not affected by GC.
446: * </p>
447: * <p>
448: * A char buffer is direct, if it is based on a byte buffer and the byte
449: * buffer is direct.
450: * </p>
451: *
452: * @return True if this buffer is direct.
453: */
454: public abstract boolean isDirect();
455:
456: /**
457: * Returns the number of remaining <code>char</code>s.
458: *
459: * @return The number of remaining <code>char</code>s.
460: */
461: public final int length() {
462: return remaining();
463: }
464:
465: /**
466: * Returns the byte order used by this buffer when converting
467: * <code>char</code>s from/to <code>byte</code>s.
468: * <p>
469: * If this buffer is not based on a byte buffer, then always return the
470: * platform's native byte order.
471: * </p>
472: *
473: * @return The byte order used by this buffer when converting
474: * <code>char</code>s from/to <code>byte</code>s.
475: */
476: public abstract ByteOrder order();
477:
478: /**
479: * Child class implements this method to realize <code>array()</code>.
480: *
481: * @return see <code>array()</code>
482: */
483: abstract char[] protectedArray();
484:
485: /**
486: * Child class implements this method to realize <code>arrayOffset()</code>.
487: *
488: * @return see <code>arrayOffset()</code>
489: */
490: abstract int protectedArrayOffset();
491:
492: /**
493: * Child class implements this method to realize <code>hasArray()</code>.
494: *
495: * @return see <code>hasArray()</code>
496: */
497: abstract boolean protectedHasArray();
498:
499: /**
500: * Writes the given char to the current position and increase the position
501: * by 1.
502: *
503: * @param c
504: * The char to write
505: * @return This buffer
506: * @exception BufferOverflowException
507: * If position is equal or greater than limit
508: * @exception ReadOnlyBufferException
509: * If no changes may be made to the contents of this buffer
510: */
511: public abstract CharBuffer put(char c);
512:
513: /**
514: * Writes <code>char</code>s in the given char array to the current
515: * position and increase the position by the number of <code>char</code>s
516: * written.
517: * <p>
518: * Calling this method has the same effect as
519: * <code>put(src, 0, src.length)</code>.
520: * </p>
521: *
522: * @param src
523: * The source char array
524: * @return This buffer
525: * @exception BufferOverflowException
526: * If <code>remaining()</code> is less than
527: * <code>src.length</code>
528: * @exception ReadOnlyBufferException
529: * If no changes may be made to the contents of this buffer
530: */
531: public final CharBuffer put(char[] src) {
532: return put(src, 0, src.length);
533: }
534:
535: /**
536: * Writes <code>char</code>s in the given char array, starting from the
537: * specified offset, to the current position and increase the position by
538: * the number of <code>char</code>s written.
539: *
540: * @param src
541: * The source char array
542: * @param off
543: * The offset of char array, must be no less than zero and no
544: * greater than <code>src.length</code>
545: * @param len
546: * The number of <code>char</code>s to write, must be no less
547: * than zero and no greater than <code>src.length - off</code>
548: * @return This buffer
549: * @exception BufferOverflowException
550: * If <code>remaining()</code> is less than
551: * <code>len</code>
552: * @exception IndexOutOfBoundsException
553: * If either <code>off</code> or <code>len</code> is
554: * invalid
555: * @exception ReadOnlyBufferException
556: * If no changes may be made to the contents of this buffer
557: */
558: public CharBuffer put(char[] src, int off, int len) {
559: int length = src.length;
560: if ((off < 0) || (len < 0) || (long) off + (long) len > length) {
561: throw new IndexOutOfBoundsException();
562: }
563:
564: if (len > remaining()) {
565: throw new BufferOverflowException();
566: }
567: for (int i = off; i < off + len; i++) {
568: put(src[i]);
569: }
570: return this ;
571: }
572:
573: /**
574: * Writes all the remaining <code>char</code>s of the <code>src</code>
575: * char buffer to this buffer's current position, and increase both buffers'
576: * position by the number of <code>char</code>s copied.
577: *
578: * @param src
579: * The source char buffer
580: * @return This buffer
581: * @exception BufferOverflowException
582: * If <code>src.remaining()</code> is greater than this
583: * buffer's <code>remaining()</code>
584: * @exception IllegalArgumentException
585: * If <code>src</code> is this buffer
586: * @exception ReadOnlyBufferException
587: * If no changes may be made to the contents of this buffer
588: */
589: public CharBuffer put(CharBuffer src) {
590: if (src == this ) {
591: throw new IllegalArgumentException();
592: }
593: if (src.remaining() > remaining()) {
594: throw new BufferOverflowException();
595: }
596:
597: char[] contents = new char[src.remaining()];
598: src.get(contents);
599: put(contents);
600: return this ;
601: }
602:
603: /**
604: * Write a char to the specified index of this buffer and the position is
605: * not changed.
606: *
607: * @param index
608: * The index, must be no less than zero and less than the limit
609: * @param c
610: * The char to write
611: * @return This buffer
612: * @exception IndexOutOfBoundsException
613: * If index is invalid
614: * @exception ReadOnlyBufferException
615: * If no changes may be made to the contents of this buffer
616: */
617: public abstract CharBuffer put(int index, char c);
618:
619: /**
620: * Write all <code>char</code>s of the give string to the current
621: * position of this buffer, and increase the position by the length of
622: * string.
623: * <p>
624: * Calling this method has the same effect as
625: * <code>put(str, 0, str.length())</code>.
626: * </p>
627: *
628: * @param str
629: * The string to write
630: * @return This buffer
631: * @exception BufferOverflowException
632: * If <code>remaining()</code> is less than the length of
633: * string
634: * @exception ReadOnlyBufferException
635: * If no changes may be made to the contents of this buffer
636: */
637: public final CharBuffer put(String str) {
638: return put(str, 0, str.length());
639: }
640:
641: /**
642: * Write <code>char</code>s of the given string to the current position
643: * of this buffer, and increase the position by the number of
644: * <code>char</code>s written.
645: *
646: * @param str
647: * The string to write
648: * @param start
649: * The first char to write, must be no less than zero and no
650: * greater than <code>str.length()</code>
651: * @param end
652: * The last char to write (excluding), must be less than
653: * <code>start</code> and no greater than
654: * <code>str.length()</code>
655: * @return This buffer
656: * @exception BufferOverflowException
657: * If <code>remaining</code> is less than
658: * <code>end - start</code>
659: * @exception IndexOutOfBoundsException
660: * If either <code>start</code> or <code>end</code> is
661: * invalid
662: * @exception ReadOnlyBufferException
663: * If no changes may be made to the contents of this buffer
664: */
665: public CharBuffer put(String str, int start, int end) {
666: int length = str.length();
667: if (start < 0 || end < start || end > length) {
668: throw new IndexOutOfBoundsException();
669: }
670:
671: if (end - start > remaining()) {
672: throw new BufferOverflowException();
673: }
674: for (int i = start; i < end; i++) {
675: put(str.charAt(i));
676: }
677: return this ;
678: }
679:
680: /**
681: * Returns a sliced buffer that shares content with this buffer.
682: * <p>
683: * The sliced buffer's capacity will be this buffer's
684: * <code>remaining()</code>, and its zero position will correspond to
685: * this buffer's current position. The new buffer's position will be 0,
686: * limit will be its capacity, and its mark is unset. The new buffer's
687: * readonly property and byte order are same as this buffer.
688: * </p>
689: * <p>
690: * The new buffer shares content with this buffer, which means either
691: * buffer's change of content will be visible to the other. The two buffer's
692: * position, limit and mark are independent.
693: * </p>
694: *
695: * @return A sliced buffer that shares content with this buffer.
696: */
697: public abstract CharBuffer slice();
698:
699: /**
700: * Returns a new char buffer represents a sub-sequence of this buffer's
701: * current remaining content.
702: * <p>
703: * The new buffer's position will be <code>position() + start</code>,
704: * limit will be <code>position() + end</code>, capacity will be same as
705: * this buffer. The new buffer's readonly property and byte order are same
706: * as this buffer.
707: * </p>
708: * <p>
709: * The new buffer shares content with this buffer, which means either
710: * buffer's change of content will be visible to the other. The two buffer's
711: * position, limit and mark are independent.
712: * </p>
713: *
714: * @param start
715: * The start index of the sub-sequence, referenced from the
716: * current buffer position. Must not be less than zero and not
717: * greater than the value obtained from a call to
718: * <code>remaining()</code>.
719: * @param end
720: * The end index of the sub-sequence, referenced from the current
721: * buffer position. Must not be less than <code>start</code>
722: * and not be greater than the value obtained from a call to
723: * <code>remaining()</code>
724: * @return A new char buffer represents a sub-sequence of this buffer's
725: * current remaining content.
726: * @exception IndexOutOfBoundsException
727: * If either <code>start</code> or <code>end</code> is
728: * invalid
729: */
730: public abstract CharSequence subSequence(int start, int end);
731:
732: /**
733: * Returns a string represents the current remaining <code>char</code>s
734: * of this buffer.
735: *
736: * @return A string represents the current remaining <code>char</code>s
737: * of this buffer.
738: */
739: @Override
740: public String toString() {
741: StringBuffer strbuf = new StringBuffer();
742: for (int i = position; i < limit; i++) {
743: strbuf.append(get(i));
744: }
745: return strbuf.toString();
746: }
747:
748: /**
749: * @see Appendable#append(char)
750: */
751: public CharBuffer append(char c) {
752: return put(c);
753: }
754:
755: /**
756: * @see Appendable#append(CharSequence)
757: */
758: public CharBuffer append(CharSequence csq) {
759: if (csq != null) {
760: return put(csq.toString());
761: }
762: return put("null"); //$NON-NLS-1$
763: }
764:
765: /**
766: * @see Appendable#append(CharSequence, int, int)
767: */
768: public CharBuffer append(CharSequence csq, int start, int end) {
769: if (csq == null) {
770: csq = "null"; //$NON-NLS-1$
771: }
772: CharSequence cs = csq.subSequence(start, end);
773: if (cs.length() > 0) {
774: return put(cs.toString());
775: }
776: return this ;
777: }
778:
779: /**
780: * @see Readable#read(CharBuffer)
781: */
782: public int read(CharBuffer target) throws IOException {
783: if (target == this ) {
784: throw new IllegalArgumentException();
785: }
786: if (remaining() == 0) {
787: return target.remaining() == 0 ? 0 : -1;
788: }
789: int result = Math.min(target.remaining(), remaining());
790: char[] chars = new char[result];
791: get(chars);
792: target.put(chars);
793: return result;
794: }
795: }
|