Home | History | Annotate | Download | only in nio
      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     long 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