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 
17 package 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  */
47 public 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      */
89     final long effectiveDirectAddress;
90 
Buffer(int elementSizeShift, int capacity, long effectiveDirectAddress)91     Buffer(int elementSizeShift, int capacity, long effectiveDirectAddress) {
92         this._elementSizeShift = elementSizeShift;
93         if (capacity < 0) {
94             throw new IllegalArgumentException("capacity < 0: " + capacity);
95         }
96         this.capacity = this.limit = capacity;
97         this.effectiveDirectAddress = effectiveDirectAddress;
98     }
99 
100     /**
101      * Returns the array that backs this buffer (optional operation).
102      * The returned value is the actual array, not a copy, so modifications
103      * to the array write through to the buffer.
104      *
105      * <p>Subclasses should override this method with a covariant return type
106      * to provide the exact type of the array.
107      *
108      * <p>Use {@code hasArray} to ensure this method won't throw.
109      * (A separate call to {@code isReadOnly} is not necessary.)
110      *
111      * @return the array
112      * @throws ReadOnlyBufferException if the buffer is read-only
113      *         UnsupportedOperationException if the buffer does not expose an array
114      * @since 1.6
115      */
array()116     public abstract Object array();
117 
118     /**
119      * Returns the offset into the array returned by {@code array} of the first
120      * element of the buffer (optional operation). The backing array (if there is one)
121      * is not necessarily the same size as the buffer, and position 0 in the buffer is
122      * not necessarily the 0th element in the array. Use
123      * {@code buffer.array()[offset + buffer.arrayOffset()} to access element {@code offset}
124      * in {@code buffer}.
125      *
126      * <p>Use {@code hasArray} to ensure this method won't throw.
127      * (A separate call to {@code isReadOnly} is not necessary.)
128      *
129      * @return the offset
130      * @throws ReadOnlyBufferException if the buffer is read-only
131      *         UnsupportedOperationException if the buffer does not expose an array
132      * @since 1.6
133      */
arrayOffset()134     public abstract int arrayOffset();
135 
136     /**
137      * Returns the capacity of this buffer.
138      *
139      * @return the number of elements that are contained in this buffer.
140      */
capacity()141     public final int capacity() {
142         return capacity;
143     }
144 
145     /**
146      * Used for the scalar get/put operations.
147      */
checkIndex(int index)148     void checkIndex(int index) {
149         if (index < 0 || index >= limit) {
150             throw new IndexOutOfBoundsException("index=" + index + ", limit=" + limit);
151         }
152     }
153 
154     /**
155      * Used for the ByteBuffer operations that get types larger than a byte.
156      */
checkIndex(int index, int sizeOfType)157     void checkIndex(int index, int sizeOfType) {
158         if (index < 0 || index > limit - sizeOfType) {
159             throw new IndexOutOfBoundsException("index=" + index + ", limit=" + limit +
160                     ", size of type=" + sizeOfType);
161         }
162     }
163 
checkGetBounds(int bytesPerElement, int length, int offset, int count)164     int checkGetBounds(int bytesPerElement, int length, int offset, int count) {
165         int byteCount = bytesPerElement * count;
166         if ((offset | count) < 0 || offset > length || length - offset < count) {
167             throw new IndexOutOfBoundsException("offset=" + offset +
168                     ", count=" + count + ", length=" + length);
169         }
170         if (byteCount > remaining()) {
171             throw new BufferUnderflowException();
172         }
173         return byteCount;
174     }
175 
checkPutBounds(int bytesPerElement, int length, int offset, int count)176     int checkPutBounds(int bytesPerElement, int length, int offset, int count) {
177         int byteCount = bytesPerElement * count;
178         if ((offset | count) < 0 || offset > length || length - offset < count) {
179             throw new IndexOutOfBoundsException("offset=" + offset +
180                     ", count=" + count + ", length=" + length);
181         }
182         if (byteCount > remaining()) {
183             throw new BufferOverflowException();
184         }
185         if (isReadOnly()) {
186             throw new ReadOnlyBufferException();
187         }
188         return byteCount;
189     }
190 
checkStartEndRemaining(int start, int end)191     void checkStartEndRemaining(int start, int end) {
192         if (end < start || start < 0 || end > remaining()) {
193             throw new IndexOutOfBoundsException("start=" + start + ", end=" + end +
194                     ", remaining()=" + remaining());
195         }
196     }
197 
198     /**
199      * Clears this buffer.
200      * <p>
201      * While the content of this buffer is not changed, the following internal
202      * changes take place: the current position is reset back to the start of
203      * the buffer, the value of the buffer limit is made equal to the capacity
204      * and mark is cleared.
205      *
206      * @return this buffer.
207      */
clear()208     public final Buffer clear() {
209         position = 0;
210         mark = UNSET_MARK;
211         limit = capacity;
212         return this;
213     }
214 
215     /**
216      * Flips this buffer.
217      * <p>
218      * The limit is set to the current position, then the position is set to
219      * zero, and the mark is cleared.
220      * <p>
221      * The content of this buffer is not changed.
222      *
223      * @return this buffer.
224      */
flip()225     public final Buffer flip() {
226         limit = position;
227         position = 0;
228         mark = UNSET_MARK;
229         return this;
230     }
231 
232     /**
233      * Returns true if {@code array} and {@code arrayOffset} won't throw. This method does not
234      * return true for buffers not backed by arrays because the other methods would throw
235      * {@code UnsupportedOperationException}, nor does it return true for buffers backed by
236      * read-only arrays, because the other methods would throw {@code ReadOnlyBufferException}.
237      * @since 1.6
238      */
hasArray()239     public abstract boolean hasArray();
240 
241     /**
242      * Indicates if there are elements remaining in this buffer, that is if
243      * {@code position < limit}.
244      *
245      * @return {@code true} if there are elements remaining in this buffer,
246      *         {@code false} otherwise.
247      */
hasRemaining()248     public final boolean hasRemaining() {
249         return position < limit;
250     }
251 
252     /**
253      * Returns true if this is a direct buffer.
254      * @since 1.6
255      */
isDirect()256     public abstract boolean isDirect();
257 
258     /**
259      * Indicates whether this buffer is read-only.
260      *
261      * @return {@code true} if this buffer is read-only, {@code false}
262      *         otherwise.
263      */
isReadOnly()264     public abstract boolean isReadOnly();
265 
checkWritable()266     final void checkWritable() {
267         if (isReadOnly()) {
268             throw new IllegalArgumentException("Read-only buffer");
269         }
270     }
271 
272     /**
273      * Returns the limit of this buffer.
274      *
275      * @return the limit of this buffer.
276      */
limit()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      * @throws IllegalArgumentException
294      *                if <code>newLimit</code> is invalid.
295      */
limit(int newLimit)296     public final Buffer limit(int newLimit) {
297         if (newLimit < 0 || newLimit > capacity) {
298             throw new IllegalArgumentException("Bad limit (capacity " + capacity + "): " + newLimit);
299         }
300 
301         limit = newLimit;
302         if (position > newLimit) {
303             position = newLimit;
304         }
305         if ((mark != UNSET_MARK) && (mark > newLimit)) {
306             mark = UNSET_MARK;
307         }
308         return this;
309     }
310 
311     /**
312      * Marks the current position, so that the position may return to this point
313      * later by calling <code>reset()</code>.
314      *
315      * @return this buffer.
316      */
mark()317     public final Buffer mark() {
318         mark = position;
319         return this;
320     }
321 
322     /**
323      * Returns the position of this buffer.
324      *
325      * @return the value of this buffer's current position.
326      */
position()327     public final int position() {
328         return position;
329     }
330 
331     /**
332      * Sets the position of this buffer.
333      * <p>
334      * If the mark is set and it is greater than the new position, then it is
335      * cleared.
336      *
337      * @param newPosition
338      *            the new position, must be not negative and not greater than
339      *            limit.
340      * @return this buffer.
341      * @throws IllegalArgumentException
342      *                if <code>newPosition</code> is invalid.
343      */
position(int newPosition)344     public final Buffer position(int newPosition) {
345         positionImpl(newPosition);
346         return this;
347     }
348 
positionImpl(int newPosition)349     void positionImpl(int newPosition) {
350         if (newPosition < 0 || newPosition > limit) {
351             throw new IllegalArgumentException("Bad position (limit " + limit + "): " + newPosition);
352         }
353 
354         position = newPosition;
355         if ((mark != UNSET_MARK) && (mark > position)) {
356             mark = UNSET_MARK;
357         }
358     }
359 
360     /**
361      * Returns the number of remaining elements in this buffer, that is
362      * {@code limit - position}.
363      *
364      * @return the number of remaining elements in this buffer.
365      */
remaining()366     public final int remaining() {
367         return limit - position;
368     }
369 
370     /**
371      * Resets the position of this buffer to the <code>mark</code>.
372      *
373      * @return this buffer.
374      * @throws InvalidMarkException
375      *                if the mark is not set.
376      */
reset()377     public final Buffer reset() {
378         if (mark == UNSET_MARK) {
379             throw new InvalidMarkException("Mark not set");
380         }
381         position = mark;
382         return this;
383     }
384 
385     /**
386      * Rewinds this buffer.
387      * <p>
388      * The position is set to zero, and the mark is cleared. The content of this
389      * buffer is not changed.
390      *
391      * @return this buffer.
392      */
rewind()393     public final Buffer rewind() {
394         position = 0;
395         mark = UNSET_MARK;
396         return this;
397     }
398 
399     /**
400      * Returns a string describing this buffer.
401      */
toString()402     @Override public String toString() {
403         return getClass().getName() +
404             "[position=" + position + ",limit=" + limit + ",capacity=" + capacity + "]";
405     }
406 
407     /** @hide for testing only */
getElementSizeShift()408     public final int getElementSizeShift() {
409         return _elementSizeShift;
410     }
411 }
412