001: /* Licensed to the Apache Software Foundation (ASF) under one or more
002: * contributor license agreements. See the NOTICE file distributed with
003: * this work for additional information regarding copyright ownership.
004: * The ASF licenses this file to You under the Apache License, Version 2.0
005: * (the "License"); you may not use this file except in compliance with
006: * the License. You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package java.nio;
018:
019: /**
020: * A buffer is a list of elements of a specific primitive type.
021: * <p>
022: * A buffer can be described by following properties:
023: * <ul>
024: * <li>Capacity, is the number of elements a buffer can hold. Capacity is no
025: * less than zero and never changes.</li>
026: * <li>Position, is a cursor of this buffer. Elements are read or write at the
027: * position if you do not specify an index explicitly. Position is no less than
028: * zero and no greater than the limit.</li>
029: * <li>Limit controls the scope of accessible elements. You can only read or
030: * write elements from index zero to <code>limit - 1</code>. Accessing
031: * elements out of the scope will cause exception. Limit is no less than zero
032: * and no greater than capacity.</li>
033: * <li>Mark, is used to remember the current position, so that you can reset
034: * the position later. Mark is no less than zero and no greater than position.</li>
035: * <li>A buffer can be readonly or read-write. Trying to modify the elements of
036: * a readonly buffer will cause <code>ReadOnlyBufferException</code>, while
037: * changing the position, limit and mark of a readonly buffer is OK.</li>
038: * <li>A buffer can be direct or indirect. A direct buffer will try its best to
039: * take advantage of native memory APIs and it may not stay in java heap, thus
040: * not affected by GC.</li>
041: * </ul>
042: * </p>
043: * <p>
044: * Buffers are not thread-safe. If concurrent access to a buffer instance is
045: * required, then the callers are responsible to take care of the
046: * synchronization issues.
047: * </p>
048: */
049: public abstract class Buffer {
050:
051: /**
052: * <code>UNSET_MARK</code> means the mark has not been set.
053: */
054: final static int UNSET_MARK = -1;
055:
056: /**
057: * The capacity of this buffer, which never change.
058: */
059: final int capacity;
060:
061: /**
062: * <code>limit - 1</code> is the last element that can be read or write.
063: * Limit must be no less than zero and no greater than <code>capacity</code>.
064: */
065: int limit;
066:
067: /**
068: * Mark is the position will be set when <code>reset()</code> is called.
069: * Mark is not set by default. Mark is always no less than zero and no
070: * greater than <code>position</code>.
071: */
072: int mark = UNSET_MARK;
073:
074: /**
075: * The current position of this buffer. Position is always no less than zero
076: * and no greater than <code>limit</code>.
077: */
078: int position = 0;
079:
080: /**
081: * Construct a buffer with the specified capacity.
082: *
083: * @param capacity
084: * The capacity of this buffer
085: */
086: Buffer(int capacity) {
087: super ();
088: if (capacity < 0) {
089: throw new IllegalArgumentException();
090: }
091: this .capacity = this .limit = capacity;
092: }
093:
094: /**
095: * Returns the capacity of this buffer.
096: *
097: * @return The number of elements that are contained in this buffer.
098: */
099: public final int capacity() {
100: return capacity;
101: }
102:
103: /**
104: * Clears this buffer.
105: * <p>
106: * While the content of this buffer is not changed the following internal
107: * changes take place : the current position is reset back to the start of
108: * the buffer, the value of the buffer limit is made equal to the capacity
109: * and mark is unset.
110: * </p>
111: *
112: * @return This buffer
113: */
114: public final Buffer clear() {
115: position = 0;
116: mark = UNSET_MARK;
117: limit = capacity;
118: return this ;
119: }
120:
121: /**
122: * Flips this buffer.
123: * <p>
124: * The limit is set to the current position, then the position is set to
125: * zero, and the mark is cleared.
126: * </p>
127: * <p>
128: * The content of this buffer is not changed.
129: * </p>
130: *
131: * @return This buffer
132: */
133: public final Buffer flip() {
134: limit = position;
135: position = 0;
136: mark = UNSET_MARK;
137: return this ;
138: }
139:
140: /**
141: * Returns true if there are remaining element(s) in this buffer.
142: * <p>
143: * Or more precisely, returns <code>position < limit</code>.
144: * </p>
145: *
146: * @return True if there are remaining element(s) in this buffer.
147: */
148: public final boolean hasRemaining() {
149: return position < limit;
150: }
151:
152: /**
153: * Returns whether this buffer is readonly or not.
154: *
155: * @return Whether this buffer is readonly or not.
156: */
157: public abstract boolean isReadOnly();
158:
159: /**
160: * Returns the limit of this buffer.
161: *
162: * @return The limit of this buffer.
163: */
164: public final int limit() {
165: return limit;
166: }
167:
168: /**
169: * Sets the limit of this buffer.
170: * <p>
171: * If the current position in the buffer is in excess of
172: * <code>newLimit</code> then, on returning from this call, it will have
173: * been adjusted to be equivalent to <code>newLimit</code>. If the mark
174: * is set and is greater than the new limit, then it is cleared.
175: * </p>
176: *
177: * @param newLimit
178: * The new limit, must be no less than zero and no greater than
179: * capacity
180: * @return This buffer
181: * @exception IllegalArgumentException
182: * If <code>newLimit</code> is invalid.
183: */
184: public final Buffer limit(int newLimit) {
185: if (newLimit < 0 || newLimit > capacity) {
186: throw new IllegalArgumentException();
187: }
188:
189: limit = newLimit;
190: if (position > newLimit) {
191: position = newLimit;
192: }
193: if ((mark != UNSET_MARK) && (mark > newLimit)) {
194: mark = UNSET_MARK;
195: }
196: return this ;
197: }
198:
199: /**
200: * Mark the current position, so that the position may return to this point
201: * later by calling <code>reset()</code>.
202: *
203: * @return This buffer
204: */
205: public final Buffer mark() {
206: mark = position;
207: return this ;
208: }
209:
210: /**
211: * Returns the position of this buffer.
212: *
213: * @return The value of this buffer's current position.
214: */
215: public final int position() {
216: return position;
217: }
218:
219: /**
220: * Sets the position of this buffer.
221: * <p>
222: * If the mark is set and is greater than the new position, then it is
223: * cleared.
224: * </p>
225: *
226: * @param newPosition
227: * The new position, must be no less than zero and no greater
228: * than limit
229: * @return This buffer
230: * @exception IllegalArgumentException
231: * If <code>newPosition</code> is invalid
232: */
233: public final Buffer position(int newPosition) {
234: if (newPosition < 0 || newPosition > limit) {
235: throw new IllegalArgumentException();
236: }
237:
238: position = newPosition;
239: if ((mark != UNSET_MARK) && (mark > position)) {
240: mark = UNSET_MARK;
241: }
242: return this ;
243: }
244:
245: /**
246: * Returns the number of remaining elements in this buffer.
247: * <p>
248: * Or more precisely, returns <code>limit - position</code>.
249: * </p>
250: *
251: * @return The number of remaining elements in this buffer.
252: */
253: public final int remaining() {
254: return limit - position;
255: }
256:
257: /**
258: * Reset the position of this buffer to the <code>mark</code>.
259: *
260: * @return This buffer
261: * @exception InvalidMarkException
262: * If the mark is not set
263: */
264: public final Buffer reset() {
265: if (mark == UNSET_MARK) {
266: throw new InvalidMarkException();
267: }
268: position = mark;
269: return this ;
270: }
271:
272: /**
273: * Rewinds this buffer.
274: * <p>
275: * The position is set to zero, and the mark is cleared.
276: * </p>
277: * <p>
278: * The content of this buffer is not changed.
279: * </p>
280: *
281: * @return This buffer
282: */
283: public final Buffer rewind() {
284: position = 0;
285: mark = UNSET_MARK;
286: return this;
287: }
288: }
|