• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      * 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 
Buffer(int elementSizeShift, int capacity, MemoryBlock block)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      */
array()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      */
arrayOffset()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      */
capacity()147     public final int capacity() {
148         return capacity;
149     }
150 
151     /**
152      * Used for the scalar get/put operations.
153      */
checkIndex(int index)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      */
checkIndex(int index, int sizeOfType)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 
checkGetBounds(int bytesPerElement, int length, int offset, int count)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 
checkPutBounds(int bytesPerElement, int length, int offset, int count)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 
checkStartEndRemaining(int start, int end)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      */
clear()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      */
flip()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      */
hasArray()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      */
hasRemaining()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      */
isDirect()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      */
isReadOnly()270     public abstract boolean isReadOnly();
271 
checkWritable()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      */
limit()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      */
limit(int newLimit)302     public final Buffer limit(int newLimit) {
303         limitImpl(newLimit);
304         return this;
305     }
306 
307     /**
308      * Subverts the fact that limit(int) is final, for the benefit of MappedByteBufferAdapter.
309      */
limitImpl(int newLimit)310     void limitImpl(int newLimit) {
311         if (newLimit < 0 || newLimit > capacity) {
312             throw new IllegalArgumentException("Bad limit (capacity " + capacity + "): " + newLimit);
313         }
314 
315         limit = newLimit;
316         if (position > newLimit) {
317             position = newLimit;
318         }
319         if ((mark != UNSET_MARK) && (mark > newLimit)) {
320             mark = UNSET_MARK;
321         }
322     }
323 
324     /**
325      * Marks the current position, so that the position may return to this point
326      * later by calling <code>reset()</code>.
327      *
328      * @return this buffer.
329      */
mark()330     public final Buffer mark() {
331         mark = position;
332         return this;
333     }
334 
335     /**
336      * Returns the position of this buffer.
337      *
338      * @return the value of this buffer's current position.
339      */
position()340     public final int position() {
341         return position;
342     }
343 
344     /**
345      * Sets the position of this buffer.
346      * <p>
347      * If the mark is set and it is greater than the new position, then it is
348      * cleared.
349      *
350      * @param newPosition
351      *            the new position, must be not negative and not greater than
352      *            limit.
353      * @return this buffer.
354      * @exception IllegalArgumentException
355      *                if <code>newPosition</code> is invalid.
356      */
position(int newPosition)357     public final Buffer position(int newPosition) {
358         positionImpl(newPosition);
359         return this;
360     }
361 
positionImpl(int newPosition)362     void positionImpl(int newPosition) {
363         if (newPosition < 0 || newPosition > limit) {
364             throw new IllegalArgumentException("Bad position (limit " + limit + "): " + newPosition);
365         }
366 
367         position = newPosition;
368         if ((mark != UNSET_MARK) && (mark > position)) {
369             mark = UNSET_MARK;
370         }
371     }
372 
373     /**
374      * Returns the number of remaining elements in this buffer, that is
375      * {@code limit - position}.
376      *
377      * @return the number of remaining elements in this buffer.
378      */
remaining()379     public final int remaining() {
380         return limit - position;
381     }
382 
383     /**
384      * Resets the position of this buffer to the <code>mark</code>.
385      *
386      * @return this buffer.
387      * @exception InvalidMarkException
388      *                if the mark is not set.
389      */
reset()390     public final Buffer reset() {
391         if (mark == UNSET_MARK) {
392             throw new InvalidMarkException("Mark not set");
393         }
394         position = mark;
395         return this;
396     }
397 
398     /**
399      * Rewinds this buffer.
400      * <p>
401      * The position is set to zero, and the mark is cleared. The content of this
402      * buffer is not changed.
403      *
404      * @return this buffer.
405      */
rewind()406     public final Buffer rewind() {
407         position = 0;
408         mark = UNSET_MARK;
409         return this;
410     }
411 
toString()412     @Override public String toString() {
413         StringBuilder buf = new StringBuilder();
414         buf.append(getClass().getName());
415         buf.append(", status: capacity=");
416         buf.append(capacity);
417         buf.append(" position=");
418         buf.append(position);
419         buf.append(" limit=");
420         buf.append(limit);
421         return buf.toString();
422     }
423 }
424