Buffer.java revision fe5da19e0e366286cd4d95f7628fe9442b9062c8
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    final void checkWritable() {
273        if (isReadOnly()) {
274            throw new IllegalArgumentException("Read-only buffer");
275        }
276    }
277
278    /**
279     * Returns the limit of this buffer.
280     *
281     * @return the limit of this buffer.
282     */
283    public final int limit() {
284        return limit;
285    }
286
287    /**
288     * Sets the limit of this buffer.
289     * <p>
290     * If the current position in the buffer is in excess of
291     * <code>newLimit</code> then, on returning from this call, it will have
292     * been adjusted to be equivalent to <code>newLimit</code>. If the mark
293     * is set and is greater than the new limit, then it is cleared.
294     *
295     * @param newLimit
296     *            the new limit, must not be negative and not greater than
297     *            capacity.
298     * @return this buffer.
299     * @exception IllegalArgumentException
300     *                if <code>newLimit</code> is invalid.
301     */
302    public final Buffer limit(int newLimit) {
303        if (newLimit < 0 || newLimit > capacity) {
304            throw new IllegalArgumentException("Bad limit (capacity " + capacity + "): " + newLimit);
305        }
306
307        limit = newLimit;
308        if (position > newLimit) {
309            position = newLimit;
310        }
311        if ((mark != UNSET_MARK) && (mark > newLimit)) {
312            mark = UNSET_MARK;
313        }
314        return this;
315    }
316
317    /**
318     * Marks the current position, so that the position may return to this point
319     * later by calling <code>reset()</code>.
320     *
321     * @return this buffer.
322     */
323    public final Buffer mark() {
324        mark = position;
325        return this;
326    }
327
328    /**
329     * Returns the position of this buffer.
330     *
331     * @return the value of this buffer's current position.
332     */
333    public final int position() {
334        return position;
335    }
336
337    /**
338     * Sets the position of this buffer.
339     * <p>
340     * If the mark is set and it is greater than the new position, then it is
341     * cleared.
342     *
343     * @param newPosition
344     *            the new position, must be not negative and not greater than
345     *            limit.
346     * @return this buffer.
347     * @exception IllegalArgumentException
348     *                if <code>newPosition</code> is invalid.
349     */
350    public final Buffer position(int newPosition) {
351        positionImpl(newPosition);
352        return this;
353    }
354
355    void positionImpl(int newPosition) {
356        if (newPosition < 0 || newPosition > limit) {
357            throw new IllegalArgumentException("Bad position (limit " + limit + "): " + newPosition);
358        }
359
360        position = newPosition;
361        if ((mark != UNSET_MARK) && (mark > position)) {
362            mark = UNSET_MARK;
363        }
364    }
365
366    /**
367     * Returns the number of remaining elements in this buffer, that is
368     * {@code limit - position}.
369     *
370     * @return the number of remaining elements in this buffer.
371     */
372    public final int remaining() {
373        return limit - position;
374    }
375
376    /**
377     * Resets the position of this buffer to the <code>mark</code>.
378     *
379     * @return this buffer.
380     * @exception InvalidMarkException
381     *                if the mark is not set.
382     */
383    public final Buffer reset() {
384        if (mark == UNSET_MARK) {
385            throw new InvalidMarkException("Mark not set");
386        }
387        position = mark;
388        return this;
389    }
390
391    /**
392     * Rewinds this buffer.
393     * <p>
394     * The position is set to zero, and the mark is cleared. The content of this
395     * buffer is not changed.
396     *
397     * @return this buffer.
398     */
399    public final Buffer rewind() {
400        position = 0;
401        mark = UNSET_MARK;
402        return this;
403    }
404
405    /**
406     * Returns a string describing this buffer.
407     */
408    @Override public String toString() {
409        return getClass().getName() +
410            "[position=" + position + ",limit=" + limit + ",capacity=" + capacity + "]";
411    }
412}
413