Buffer.java revision a28bc96d63595a77fa918da8ccdda50e9eaae95e
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package java.nio;
18
19/**
20 * A buffer is a list of elements of a specific primitive type.
21 * <p>
22 * A buffer can be described by the following properties:
23 * <ul>
24 * <li>Capacity: the number of elements a buffer can hold. Capacity may not be
25 * negative and never changes.</li>
26 * <li>Position: a cursor of this buffer. Elements are read or written at the
27 * position if you do not specify an index explicitly. Position may not be
28 * negative and not greater than the limit.</li>
29 * <li>Limit: controls the scope of accessible elements. You can only read or
30 * write elements from index zero to <code>limit - 1</code>. Accessing
31 * elements out of the scope will cause an exception. Limit may not be negative
32 * and not greater than capacity.</li>
33 * <li>Mark: used to remember the current position, so that you can reset the
34 * position later. Mark may not be negative and no greater than position.</li>
35 * <li>A buffer can be read-only or read-write. Trying to modify the elements
36 * of a read-only buffer will cause a <code>ReadOnlyBufferException</code>,
37 * while changing the position, limit and mark of a read-only buffer is OK.</li>
38 * <li>A buffer can be direct or indirect. A direct buffer will try its best to
39 * take advantage of native memory APIs and it may not stay in the Java heap,
40 * thus it is not affected by garbage collection.</li>
41 * </ul>
42 * <p>
43 * Buffers are not thread-safe. If concurrent access to a buffer instance is
44 * required, then the callers are responsible to take care of the
45 * synchronization issues.
46 */
47public abstract class Buffer {
48    /**
49     * <code>UNSET_MARK</code> means the mark has not been set.
50     */
51    static final int UNSET_MARK = -1;
52
53    /**
54     * The capacity of this buffer, which never changes.
55     */
56    final int capacity;
57
58    /**
59     * <code>limit - 1</code> is the last element that can be read or written.
60     * Limit must be no less than zero and no greater than <code>capacity</code>.
61     */
62    int limit;
63
64    /**
65     * Mark is where position will be set when <code>reset()</code> is called.
66     * Mark is not set by default. Mark is always no less than zero and no
67     * greater than <code>position</code>.
68     */
69    int mark = UNSET_MARK;
70
71    /**
72     * The current position of this buffer. Position is always no less than zero
73     * and no greater than <code>limit</code>.
74     */
75    int position = 0;
76
77    /**
78     * The log base 2 of the element size of this buffer.  Each typed subclass
79     * (ByteBuffer, CharBuffer, etc.) is responsible for initializing this
80     * value.  The value is used by JNI code in frameworks/base/ to avoid the
81     * need for costly 'instanceof' tests.
82     */
83    final int _elementSizeShift;
84
85    /**
86     * For direct buffers, the effective address of the data; zero otherwise.
87     * This is set in the constructor.
88     * TODO: make this final at the cost of loads of extra constructors? [how many?]
89     */
90    int effectiveDirectAddress;
91
92    /**
93     * For direct buffers, the underlying MemoryBlock; null otherwise.
94     */
95    final MemoryBlock block;
96
97    Buffer(int elementSizeShift, int capacity, MemoryBlock block) {
98        this._elementSizeShift = elementSizeShift;
99        if (capacity < 0) {
100            throw new IllegalArgumentException("capacity < 0: " + capacity);
101        }
102        this.capacity = this.limit = capacity;
103        this.block = block;
104    }
105
106    /**
107     * Returns the array that backs this buffer (optional operation).
108     * The returned value is the actual array, not a copy, so modifications
109     * to the array write through to the buffer.
110     *
111     * <p>Subclasses should override this method with a covariant return type
112     * to provide the exact type of the array.
113     *
114     * <p>Use {@code hasArray} to ensure this method won't throw.
115     * (A separate call to {@code isReadOnly} is not necessary.)
116     *
117     * @return the array
118     * @throws ReadOnlyBufferException if the buffer is read-only
119     *         UnsupportedOperationException if the buffer does not expose an array
120     * @since 1.6
121     */
122    public abstract Object array();
123
124    /**
125     * Returns the offset into the array returned by {@code array} of the first
126     * element of the buffer (optional operation). The backing array (if there is one)
127     * is not necessarily the same size as the buffer, and position 0 in the buffer is
128     * not necessarily the 0th element in the array. Use
129     * {@code buffer.array()[offset + buffer.arrayOffset()} to access element {@code offset}
130     * in {@code buffer}.
131     *
132     * <p>Use {@code hasArray} to ensure this method won't throw.
133     * (A separate call to {@code isReadOnly} is not necessary.)
134     *
135     * @return the offset
136     * @throws ReadOnlyBufferException if the buffer is read-only
137     *         UnsupportedOperationException if the buffer does not expose an array
138     * @since 1.6
139     */
140    public abstract int arrayOffset();
141
142    /**
143     * Returns the capacity of this buffer.
144     *
145     * @return the number of elements that are contained in this buffer.
146     */
147    public final int capacity() {
148        return capacity;
149    }
150
151    /**
152     * Used for the scalar get/put operations.
153     */
154    void checkIndex(int index) {
155        if (index < 0 || index >= limit) {
156            throw new IndexOutOfBoundsException("index=" + index + ", limit=" + limit);
157        }
158    }
159
160    /**
161     * Used for the ByteBuffer operations that get types larger than a byte.
162     */
163    void checkIndex(int index, int sizeOfType) {
164        if (index < 0 || index > limit - sizeOfType) {
165            throw new IndexOutOfBoundsException("index=" + index + ", limit=" + limit +
166                    ", size of type=" + sizeOfType);
167        }
168    }
169
170    int checkGetBounds(int bytesPerElement, int length, int offset, int count) {
171        int byteCount = bytesPerElement * count;
172        if ((offset | count) < 0 || offset > length || length - offset < count) {
173            throw new IndexOutOfBoundsException("offset=" + offset +
174                    ", count=" + count + ", length=" + length);
175        }
176        if (byteCount > remaining()) {
177            throw new BufferUnderflowException();
178        }
179        return byteCount;
180    }
181
182    int checkPutBounds(int bytesPerElement, int length, int offset, int count) {
183        int byteCount = bytesPerElement * count;
184        if ((offset | count) < 0 || offset > length || length - offset < count) {
185            throw new IndexOutOfBoundsException("offset=" + offset +
186                    ", count=" + count + ", length=" + length);
187        }
188        if (byteCount > remaining()) {
189            throw new BufferOverflowException();
190        }
191        if (isReadOnly()) {
192            throw new ReadOnlyBufferException();
193        }
194        return byteCount;
195    }
196
197    void checkStartEndRemaining(int start, int end) {
198        if (end < start || start < 0 || end > remaining()) {
199            throw new IndexOutOfBoundsException("start=" + start + ", end=" + end +
200                    ", remaining()=" + remaining());
201        }
202    }
203
204    /**
205     * Clears this buffer.
206     * <p>
207     * While the content of this buffer is not changed, the following internal
208     * changes take place: the current position is reset back to the start of
209     * the buffer, the value of the buffer limit is made equal to the capacity
210     * and mark is cleared.
211     *
212     * @return this buffer.
213     */
214    public final Buffer clear() {
215        position = 0;
216        mark = UNSET_MARK;
217        limit = capacity;
218        return this;
219    }
220
221    /**
222     * Flips this buffer.
223     * <p>
224     * The limit is set to the current position, then the position is set to
225     * zero, and the mark is cleared.
226     * <p>
227     * The content of this buffer is not changed.
228     *
229     * @return this buffer.
230     */
231    public final Buffer flip() {
232        limit = position;
233        position = 0;
234        mark = UNSET_MARK;
235        return this;
236    }
237
238    /**
239     * Returns true if {@code array} and {@code arrayOffset} won't throw. This method does not
240     * return true for buffers not backed by arrays because the other methods would throw
241     * {@code UnsupportedOperationException}, nor does it return true for buffers backed by
242     * read-only arrays, because the other methods would throw {@code ReadOnlyBufferException}.
243     * @since 1.6
244     */
245    public abstract boolean hasArray();
246
247    /**
248     * Indicates if there are elements remaining in this buffer, that is if
249     * {@code position < limit}.
250     *
251     * @return {@code true} if there are elements remaining in this buffer,
252     *         {@code false} otherwise.
253     */
254    public final boolean hasRemaining() {
255        return position < limit;
256    }
257
258    /**
259     * Returns true if this is a direct buffer.
260     * @since 1.6
261     */
262    public abstract boolean isDirect();
263
264    /**
265     * Indicates whether this buffer is read-only.
266     *
267     * @return {@code true} if this buffer is read-only, {@code false}
268     *         otherwise.
269     */
270    public abstract boolean isReadOnly();
271
272    /**
273     * Returns the limit of this buffer.
274     *
275     * @return the limit of this buffer.
276     */
277    public final int limit() {
278        return limit;
279    }
280
281    /**
282     * Sets the limit of this buffer.
283     * <p>
284     * If the current position in the buffer is in excess of
285     * <code>newLimit</code> then, on returning from this call, it will have
286     * been adjusted to be equivalent to <code>newLimit</code>. If the mark
287     * is set and is greater than the new limit, then it is cleared.
288     *
289     * @param newLimit
290     *            the new limit, must not be negative and not greater than
291     *            capacity.
292     * @return this buffer.
293     * @exception IllegalArgumentException
294     *                if <code>newLimit</code> is invalid.
295     */
296    public final Buffer limit(int newLimit) {
297        limitImpl(newLimit);
298        return this;
299    }
300
301    /**
302     * Subverts the fact that limit(int) is final, for the benefit of MappedByteBufferAdapter.
303     */
304    void limitImpl(int newLimit) {
305        if (newLimit < 0 || newLimit > capacity) {
306            throw new IllegalArgumentException("Bad limit (capacity " + capacity + "): " + newLimit);
307        }
308
309        limit = newLimit;
310        if (position > newLimit) {
311            position = newLimit;
312        }
313        if ((mark != UNSET_MARK) && (mark > newLimit)) {
314            mark = UNSET_MARK;
315        }
316    }
317
318    /**
319     * Marks the current position, so that the position may return to this point
320     * later by calling <code>reset()</code>.
321     *
322     * @return this buffer.
323     */
324    public final Buffer mark() {
325        mark = position;
326        return this;
327    }
328
329    /**
330     * Returns the position of this buffer.
331     *
332     * @return the value of this buffer's current position.
333     */
334    public final int position() {
335        return position;
336    }
337
338    /**
339     * Sets the position of this buffer.
340     * <p>
341     * If the mark is set and it is greater than the new position, then it is
342     * cleared.
343     *
344     * @param newPosition
345     *            the new position, must be not negative and not greater than
346     *            limit.
347     * @return this buffer.
348     * @exception IllegalArgumentException
349     *                if <code>newPosition</code> is invalid.
350     */
351    public final Buffer position(int newPosition) {
352        positionImpl(newPosition);
353        return this;
354    }
355
356    void positionImpl(int newPosition) {
357        if (newPosition < 0 || newPosition > limit) {
358            throw new IllegalArgumentException("Bad position (limit " + limit + "): " + newPosition);
359        }
360
361        position = newPosition;
362        if ((mark != UNSET_MARK) && (mark > position)) {
363            mark = UNSET_MARK;
364        }
365    }
366
367    /**
368     * Returns the number of remaining elements in this buffer, that is
369     * {@code limit - position}.
370     *
371     * @return the number of remaining elements in this buffer.
372     */
373    public final int remaining() {
374        return limit - position;
375    }
376
377    /**
378     * Resets the position of this buffer to the <code>mark</code>.
379     *
380     * @return this buffer.
381     * @exception InvalidMarkException
382     *                if the mark is not set.
383     */
384    public final Buffer reset() {
385        if (mark == UNSET_MARK) {
386            throw new InvalidMarkException("Mark not set");
387        }
388        position = mark;
389        return this;
390    }
391
392    /**
393     * Rewinds this buffer.
394     * <p>
395     * The position is set to zero, and the mark is cleared. The content of this
396     * buffer is not changed.
397     *
398     * @return this buffer.
399     */
400    public final Buffer rewind() {
401        position = 0;
402        mark = UNSET_MARK;
403        return this;
404    }
405
406    @Override public String toString() {
407        StringBuilder buf = new StringBuilder();
408        buf.append(getClass().getName());
409        buf.append(", status: capacity=");
410        buf.append(capacity);
411        buf.append(" position=");
412        buf.append(position);
413        buf.append(" limit=");
414        buf.append(limit);
415        return buf.toString();
416    }
417}
418