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