1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.nio; 19 20 import java.nio.channels.FileChannel.MapMode; 21 22 import libcore.io.Memory; 23 import libcore.io.SizeOf; 24 25 class DirectByteBuffer extends MappedByteBuffer { 26 // This is the offset into {@code Buffer.block} at which this buffer logically starts. 27 // TODO: rewrite this so we set 'block' to an OffsetMemoryBlock? 28 protected final int offset; 29 30 private final boolean isReadOnly; 31 32 protected DirectByteBuffer(MemoryBlock block, int capacity, int offset, boolean isReadOnly, MapMode mapMode) { 33 super(block, capacity, mapMode); 34 35 long baseSize = block.getSize(); 36 if (baseSize >= 0 && (capacity + offset) > baseSize) { 37 throw new IllegalArgumentException("capacity + offset > baseSize"); 38 } 39 40 this.effectiveDirectAddress = block.toLong() + offset; 41 42 this.offset = offset; 43 this.isReadOnly = isReadOnly; 44 } 45 46 // Used by the JNI NewDirectByteBuffer function. 47 DirectByteBuffer(long address, int capacity) { 48 this(MemoryBlock.wrapFromJni(address, capacity), capacity, 0, false, null); 49 } 50 51 private static DirectByteBuffer copy(DirectByteBuffer other, int markOfOther, boolean isReadOnly) { 52 DirectByteBuffer buf = new DirectByteBuffer(other.block, other.capacity(), other.offset, isReadOnly, other.mapMode); 53 buf.limit = other.limit; 54 buf.position = other.position(); 55 buf.mark = markOfOther; 56 return buf; 57 } 58 59 @Override public ByteBuffer asReadOnlyBuffer() { 60 return copy(this, mark, true); 61 } 62 63 @Override public ByteBuffer compact() { 64 if (isReadOnly) { 65 throw new ReadOnlyBufferException(); 66 } 67 Memory.memmove(this, 0, this, position, remaining()); 68 position = limit - position; 69 limit = capacity; 70 mark = UNSET_MARK; 71 return this; 72 } 73 74 @Override public ByteBuffer duplicate() { 75 return copy(this, mark, isReadOnly); 76 } 77 78 @Override public ByteBuffer slice() { 79 return new DirectByteBuffer(block, remaining(), offset + position, isReadOnly, mapMode); 80 } 81 82 @Override public boolean isReadOnly() { 83 return isReadOnly; 84 } 85 86 @Override byte[] protectedArray() { 87 if (isReadOnly) { 88 throw new ReadOnlyBufferException(); 89 } 90 byte[] array = this.block.array(); 91 if (array == null) { 92 throw new UnsupportedOperationException(); 93 } 94 return array; 95 } 96 97 @Override int protectedArrayOffset() { 98 protectedArray(); // Throw if we don't have an array or are read-only. 99 return offset; 100 } 101 102 @Override boolean protectedHasArray() { 103 return !isReadOnly && (block.array() != null); 104 } 105 106 @Override public final ByteBuffer get(byte[] dst, int dstOffset, int byteCount) { 107 checkGetBounds(1, dst.length, dstOffset, byteCount); 108 this.block.peekByteArray(offset + position, dst, dstOffset, byteCount); 109 position += byteCount; 110 return this; 111 } 112 113 final void get(char[] dst, int dstOffset, int charCount) { 114 int byteCount = checkGetBounds(SizeOf.CHAR, dst.length, dstOffset, charCount); 115 this.block.peekCharArray(offset + position, dst, dstOffset, charCount, order.needsSwap); 116 position += byteCount; 117 } 118 119 final void get(double[] dst, int dstOffset, int doubleCount) { 120 int byteCount = checkGetBounds(SizeOf.DOUBLE, dst.length, dstOffset, doubleCount); 121 this.block.peekDoubleArray(offset + position, dst, dstOffset, doubleCount, order.needsSwap); 122 position += byteCount; 123 } 124 125 final void get(float[] dst, int dstOffset, int floatCount) { 126 int byteCount = checkGetBounds(SizeOf.FLOAT, dst.length, dstOffset, floatCount); 127 this.block.peekFloatArray(offset + position, dst, dstOffset, floatCount, order.needsSwap); 128 position += byteCount; 129 } 130 131 final void get(int[] dst, int dstOffset, int intCount) { 132 int byteCount = checkGetBounds(SizeOf.INT, dst.length, dstOffset, intCount); 133 this.block.peekIntArray(offset + position, dst, dstOffset, intCount, order.needsSwap); 134 position += byteCount; 135 } 136 137 final void get(long[] dst, int dstOffset, int longCount) { 138 int byteCount = checkGetBounds(SizeOf.LONG, dst.length, dstOffset, longCount); 139 this.block.peekLongArray(offset + position, dst, dstOffset, longCount, order.needsSwap); 140 position += byteCount; 141 } 142 143 final void get(short[] dst, int dstOffset, int shortCount) { 144 int byteCount = checkGetBounds(SizeOf.SHORT, dst.length, dstOffset, shortCount); 145 this.block.peekShortArray(offset + position, dst, dstOffset, shortCount, order.needsSwap); 146 position += byteCount; 147 } 148 149 @Override public final byte get() { 150 if (position == limit) { 151 throw new BufferUnderflowException(); 152 } 153 return this.block.peekByte(offset + position++); 154 } 155 156 @Override public final byte get(int index) { 157 checkIndex(index); 158 return this.block.peekByte(offset + index); 159 } 160 161 @Override public final char getChar() { 162 int newPosition = position + SizeOf.CHAR; 163 if (newPosition > limit) { 164 throw new BufferUnderflowException(); 165 } 166 char result = (char) this.block.peekShort(offset + position, order); 167 position = newPosition; 168 return result; 169 } 170 171 @Override public final char getChar(int index) { 172 checkIndex(index, SizeOf.CHAR); 173 return (char) this.block.peekShort(offset + index, order); 174 } 175 176 @Override public final double getDouble() { 177 int newPosition = position + SizeOf.DOUBLE; 178 if (newPosition > limit) { 179 throw new BufferUnderflowException(); 180 } 181 double result = Double.longBitsToDouble(this.block.peekLong(offset + position, order)); 182 position = newPosition; 183 return result; 184 } 185 186 @Override public final double getDouble(int index) { 187 checkIndex(index, SizeOf.DOUBLE); 188 return Double.longBitsToDouble(this.block.peekLong(offset + index, order)); 189 } 190 191 @Override public final float getFloat() { 192 int newPosition = position + SizeOf.FLOAT; 193 if (newPosition > limit) { 194 throw new BufferUnderflowException(); 195 } 196 float result = Float.intBitsToFloat(this.block.peekInt(offset + position, order)); 197 position = newPosition; 198 return result; 199 } 200 201 @Override public final float getFloat(int index) { 202 checkIndex(index, SizeOf.FLOAT); 203 return Float.intBitsToFloat(this.block.peekInt(offset + index, order)); 204 } 205 206 @Override public final int getInt() { 207 int newPosition = position + SizeOf.INT; 208 if (newPosition > limit) { 209 throw new BufferUnderflowException(); 210 } 211 int result = this.block.peekInt(offset + position, order); 212 position = newPosition; 213 return result; 214 } 215 216 @Override public final int getInt(int index) { 217 checkIndex(index, SizeOf.INT); 218 return this.block.peekInt(offset + index, order); 219 } 220 221 @Override public final long getLong() { 222 int newPosition = position + SizeOf.LONG; 223 if (newPosition > limit) { 224 throw new BufferUnderflowException(); 225 } 226 long result = this.block.peekLong(offset + position, order); 227 position = newPosition; 228 return result; 229 } 230 231 @Override public final long getLong(int index) { 232 checkIndex(index, SizeOf.LONG); 233 return this.block.peekLong(offset + index, order); 234 } 235 236 @Override public final short getShort() { 237 int newPosition = position + SizeOf.SHORT; 238 if (newPosition > limit) { 239 throw new BufferUnderflowException(); 240 } 241 short result = this.block.peekShort(offset + position, order); 242 position = newPosition; 243 return result; 244 } 245 246 @Override public final short getShort(int index) { 247 checkIndex(index, SizeOf.SHORT); 248 return this.block.peekShort(offset + index, order); 249 } 250 251 @Override public final boolean isDirect() { 252 return true; 253 } 254 255 public final void free() { 256 block.free(); 257 } 258 259 @Override public final CharBuffer asCharBuffer() { 260 return ByteBufferAsCharBuffer.asCharBuffer(this); 261 } 262 263 @Override public final DoubleBuffer asDoubleBuffer() { 264 return ByteBufferAsDoubleBuffer.asDoubleBuffer(this); 265 } 266 267 @Override public final FloatBuffer asFloatBuffer() { 268 return ByteBufferAsFloatBuffer.asFloatBuffer(this); 269 } 270 271 @Override public final IntBuffer asIntBuffer() { 272 return ByteBufferAsIntBuffer.asIntBuffer(this); 273 } 274 275 @Override public final LongBuffer asLongBuffer() { 276 return ByteBufferAsLongBuffer.asLongBuffer(this); 277 } 278 279 @Override public final ShortBuffer asShortBuffer() { 280 return ByteBufferAsShortBuffer.asShortBuffer(this); 281 } 282 283 @Override public ByteBuffer put(byte value) { 284 if (isReadOnly) { 285 throw new ReadOnlyBufferException(); 286 } 287 if (position == limit) { 288 throw new BufferOverflowException(); 289 } 290 this.block.pokeByte(offset + position++, value); 291 return this; 292 } 293 294 @Override public ByteBuffer put(int index, byte value) { 295 if (isReadOnly) { 296 throw new ReadOnlyBufferException(); 297 } 298 checkIndex(index); 299 this.block.pokeByte(offset + index, value); 300 return this; 301 } 302 303 @Override public ByteBuffer put(byte[] src, int srcOffset, int byteCount) { 304 if (isReadOnly) { 305 throw new ReadOnlyBufferException(); 306 } 307 checkPutBounds(1, src.length, srcOffset, byteCount); 308 this.block.pokeByteArray(offset + position, src, srcOffset, byteCount); 309 position += byteCount; 310 return this; 311 } 312 313 final void put(char[] src, int srcOffset, int charCount) { 314 int byteCount = checkPutBounds(SizeOf.CHAR, src.length, srcOffset, charCount); 315 this.block.pokeCharArray(offset + position, src, srcOffset, charCount, order.needsSwap); 316 position += byteCount; 317 } 318 319 final void put(double[] src, int srcOffset, int doubleCount) { 320 int byteCount = checkPutBounds(SizeOf.DOUBLE, src.length, srcOffset, doubleCount); 321 this.block.pokeDoubleArray(offset + position, src, srcOffset, doubleCount, order.needsSwap); 322 position += byteCount; 323 } 324 325 final void put(float[] src, int srcOffset, int floatCount) { 326 int byteCount = checkPutBounds(SizeOf.FLOAT, src.length, srcOffset, floatCount); 327 this.block.pokeFloatArray(offset + position, src, srcOffset, floatCount, order.needsSwap); 328 position += byteCount; 329 } 330 331 final void put(int[] src, int srcOffset, int intCount) { 332 int byteCount = checkPutBounds(SizeOf.INT, src.length, srcOffset, intCount); 333 this.block.pokeIntArray(offset + position, src, srcOffset, intCount, order.needsSwap); 334 position += byteCount; 335 } 336 337 final void put(long[] src, int srcOffset, int longCount) { 338 int byteCount = checkPutBounds(SizeOf.LONG, src.length, srcOffset, longCount); 339 this.block.pokeLongArray(offset + position, src, srcOffset, longCount, order.needsSwap); 340 position += byteCount; 341 } 342 343 final void put(short[] src, int srcOffset, int shortCount) { 344 int byteCount = checkPutBounds(SizeOf.SHORT, src.length, srcOffset, shortCount); 345 this.block.pokeShortArray(offset + position, src, srcOffset, shortCount, order.needsSwap); 346 position += byteCount; 347 } 348 349 @Override public ByteBuffer putChar(char value) { 350 if (isReadOnly) { 351 throw new ReadOnlyBufferException(); 352 } 353 int newPosition = position + SizeOf.CHAR; 354 if (newPosition > limit) { 355 throw new BufferOverflowException(); 356 } 357 this.block.pokeShort(offset + position, (short) value, order); 358 position = newPosition; 359 return this; 360 } 361 362 @Override public ByteBuffer putChar(int index, char value) { 363 if (isReadOnly) { 364 throw new ReadOnlyBufferException(); 365 } 366 checkIndex(index, SizeOf.CHAR); 367 this.block.pokeShort(offset + index, (short) value, order); 368 return this; 369 } 370 371 @Override public ByteBuffer putDouble(double value) { 372 if (isReadOnly) { 373 throw new ReadOnlyBufferException(); 374 } 375 int newPosition = position + SizeOf.DOUBLE; 376 if (newPosition > limit) { 377 throw new BufferOverflowException(); 378 } 379 this.block.pokeLong(offset + position, Double.doubleToRawLongBits(value), order); 380 position = newPosition; 381 return this; 382 } 383 384 @Override public ByteBuffer putDouble(int index, double value) { 385 if (isReadOnly) { 386 throw new ReadOnlyBufferException(); 387 } 388 checkIndex(index, SizeOf.DOUBLE); 389 this.block.pokeLong(offset + index, Double.doubleToRawLongBits(value), order); 390 return this; 391 } 392 393 @Override public ByteBuffer putFloat(float value) { 394 if (isReadOnly) { 395 throw new ReadOnlyBufferException(); 396 } 397 int newPosition = position + SizeOf.FLOAT; 398 if (newPosition > limit) { 399 throw new BufferOverflowException(); 400 } 401 this.block.pokeInt(offset + position, Float.floatToRawIntBits(value), order); 402 position = newPosition; 403 return this; 404 } 405 406 @Override public ByteBuffer putFloat(int index, float value) { 407 if (isReadOnly) { 408 throw new ReadOnlyBufferException(); 409 } 410 checkIndex(index, SizeOf.FLOAT); 411 this.block.pokeInt(offset + index, Float.floatToRawIntBits(value), order); 412 return this; 413 } 414 415 @Override public ByteBuffer putInt(int value) { 416 if (isReadOnly) { 417 throw new ReadOnlyBufferException(); 418 } 419 int newPosition = position + SizeOf.INT; 420 if (newPosition > limit) { 421 throw new BufferOverflowException(); 422 } 423 this.block.pokeInt(offset + position, value, order); 424 position = newPosition; 425 return this; 426 } 427 428 @Override public ByteBuffer putInt(int index, int value) { 429 if (isReadOnly) { 430 throw new ReadOnlyBufferException(); 431 } 432 checkIndex(index, SizeOf.INT); 433 this.block.pokeInt(offset + index, value, order); 434 return this; 435 } 436 437 @Override public ByteBuffer putLong(long value) { 438 if (isReadOnly) { 439 throw new ReadOnlyBufferException(); 440 } 441 int newPosition = position + SizeOf.LONG; 442 if (newPosition > limit) { 443 throw new BufferOverflowException(); 444 } 445 this.block.pokeLong(offset + position, value, order); 446 position = newPosition; 447 return this; 448 } 449 450 @Override public ByteBuffer putLong(int index, long value) { 451 if (isReadOnly) { 452 throw new ReadOnlyBufferException(); 453 } 454 checkIndex(index, SizeOf.LONG); 455 this.block.pokeLong(offset + index, value, order); 456 return this; 457 } 458 459 @Override public ByteBuffer putShort(short value) { 460 if (isReadOnly) { 461 throw new ReadOnlyBufferException(); 462 } 463 int newPosition = position + SizeOf.SHORT; 464 if (newPosition > limit) { 465 throw new BufferOverflowException(); 466 } 467 this.block.pokeShort(offset + position, value, order); 468 position = newPosition; 469 return this; 470 } 471 472 @Override public ByteBuffer putShort(int index, short value) { 473 if (isReadOnly) { 474 throw new ReadOnlyBufferException(); 475 } 476 checkIndex(index, SizeOf.SHORT); 477 this.block.pokeShort(offset + index, value, order); 478 return this; 479 } 480 } 481