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 18package java.nio; 19 20import libcore.io.SizeOf; 21import libcore.io.Memory; 22 23/** 24 * ByteArrayBuffer implements byte[]-backed ByteBuffers. 25 */ 26final class ByteArrayBuffer extends ByteBuffer { 27 28 /** 29 * These fields are non-private for NioUtils.unsafeArray. 30 */ 31 final byte[] backingArray; 32 final int arrayOffset; 33 34 private final boolean isReadOnly; 35 36 ByteArrayBuffer(byte[] backingArray) { 37 this(backingArray.length, backingArray, 0, false); 38 } 39 40 private ByteArrayBuffer(int capacity, byte[] backingArray, int arrayOffset, boolean isReadOnly) { 41 super(capacity, 0); 42 this.backingArray = backingArray; 43 this.arrayOffset = arrayOffset; 44 this.isReadOnly = isReadOnly; 45 if (arrayOffset + capacity > backingArray.length) { 46 throw new IndexOutOfBoundsException("backingArray.length=" + backingArray.length + 47 ", capacity=" + capacity + ", arrayOffset=" + arrayOffset); 48 } 49 } 50 51 private static ByteArrayBuffer copy(ByteArrayBuffer other, int markOfOther, boolean isReadOnly) { 52 ByteArrayBuffer buf = new ByteArrayBuffer(other.capacity(), other.backingArray, other.arrayOffset, isReadOnly); 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 System.arraycopy(backingArray, position + arrayOffset, backingArray, arrayOffset, 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 ByteArrayBuffer(remaining(), backingArray, arrayOffset + position, isReadOnly); 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 return backingArray; 91 } 92 93 @Override int protectedArrayOffset() { 94 if (isReadOnly) { 95 throw new ReadOnlyBufferException(); 96 } 97 return arrayOffset; 98 } 99 100 @Override boolean protectedHasArray() { 101 if (isReadOnly) { 102 return false; 103 } 104 return true; 105 } 106 107 @Override public final ByteBuffer get(byte[] dst, int dstOffset, int byteCount) { 108 checkGetBounds(1, dst.length, dstOffset, byteCount); 109 System.arraycopy(backingArray, arrayOffset + position, dst, dstOffset, byteCount); 110 position += byteCount; 111 return this; 112 } 113 114 final void get(char[] dst, int dstOffset, int charCount) { 115 int byteCount = checkGetBounds(SizeOf.CHAR, dst.length, dstOffset, charCount); 116 Memory.unsafeBulkGet(dst, dstOffset, byteCount, backingArray, arrayOffset + position, SizeOf.CHAR, order.needsSwap); 117 position += byteCount; 118 } 119 120 final void get(double[] dst, int dstOffset, int doubleCount) { 121 int byteCount = checkGetBounds(SizeOf.DOUBLE, dst.length, dstOffset, doubleCount); 122 Memory.unsafeBulkGet(dst, dstOffset, byteCount, backingArray, arrayOffset + position, SizeOf.DOUBLE, order.needsSwap); 123 position += byteCount; 124 } 125 126 final void get(float[] dst, int dstOffset, int floatCount) { 127 int byteCount = checkGetBounds(SizeOf.FLOAT, dst.length, dstOffset, floatCount); 128 Memory.unsafeBulkGet(dst, dstOffset, byteCount, backingArray, arrayOffset + position, SizeOf.FLOAT, order.needsSwap); 129 position += byteCount; 130 } 131 132 final void get(int[] dst, int dstOffset, int intCount) { 133 int byteCount = checkGetBounds(SizeOf.INT, dst.length, dstOffset, intCount); 134 Memory.unsafeBulkGet(dst, dstOffset, byteCount, backingArray, arrayOffset + position, SizeOf.INT, order.needsSwap); 135 position += byteCount; 136 } 137 138 final void get(long[] dst, int dstOffset, int longCount) { 139 int byteCount = checkGetBounds(SizeOf.LONG, dst.length, dstOffset, longCount); 140 Memory.unsafeBulkGet(dst, dstOffset, byteCount, backingArray, arrayOffset + position, SizeOf.LONG, order.needsSwap); 141 position += byteCount; 142 } 143 144 final void get(short[] dst, int dstOffset, int shortCount) { 145 int byteCount = checkGetBounds(SizeOf.SHORT, dst.length, dstOffset, shortCount); 146 Memory.unsafeBulkGet(dst, dstOffset, byteCount, backingArray, arrayOffset + position, SizeOf.SHORT, order.needsSwap); 147 position += byteCount; 148 } 149 150 @Override public final byte get() { 151 if (position == limit) { 152 throw new BufferUnderflowException(); 153 } 154 return backingArray[arrayOffset + position++]; 155 } 156 157 @Override public final byte get(int index) { 158 checkIndex(index); 159 return backingArray[arrayOffset + index]; 160 } 161 162 @Override public final char getChar() { 163 int newPosition = position + SizeOf.CHAR; 164 if (newPosition > limit) { 165 throw new BufferUnderflowException(); 166 } 167 char result = (char) Memory.peekShort(backingArray, arrayOffset + position, order); 168 position = newPosition; 169 return result; 170 } 171 172 @Override public final char getChar(int index) { 173 checkIndex(index, SizeOf.CHAR); 174 return (char) Memory.peekShort(backingArray, arrayOffset + index, order); 175 } 176 177 @Override public final double getDouble() { 178 return Double.longBitsToDouble(getLong()); 179 } 180 181 @Override public final double getDouble(int index) { 182 return Double.longBitsToDouble(getLong(index)); 183 } 184 185 @Override public final float getFloat() { 186 return Float.intBitsToFloat(getInt()); 187 } 188 189 @Override public final float getFloat(int index) { 190 return Float.intBitsToFloat(getInt(index)); 191 } 192 193 @Override public final int getInt() { 194 int newPosition = position + SizeOf.INT; 195 if (newPosition > limit) { 196 throw new BufferUnderflowException(); 197 } 198 int result = Memory.peekInt(backingArray, arrayOffset + position, order); 199 position = newPosition; 200 return result; 201 } 202 203 @Override public final int getInt(int index) { 204 checkIndex(index, SizeOf.INT); 205 return Memory.peekInt(backingArray, arrayOffset + index, order); 206 } 207 208 @Override public final long getLong() { 209 int newPosition = position + SizeOf.LONG; 210 if (newPosition > limit) { 211 throw new BufferUnderflowException(); 212 } 213 long result = Memory.peekLong(backingArray, arrayOffset + position, order); 214 position = newPosition; 215 return result; 216 } 217 218 @Override public final long getLong(int index) { 219 checkIndex(index, SizeOf.LONG); 220 return Memory.peekLong(backingArray, arrayOffset + index, order); 221 } 222 223 @Override public final short getShort() { 224 int newPosition = position + SizeOf.SHORT; 225 if (newPosition > limit) { 226 throw new BufferUnderflowException(); 227 } 228 short result = Memory.peekShort(backingArray, arrayOffset + position, order); 229 position = newPosition; 230 return result; 231 } 232 233 @Override public final short getShort(int index) { 234 checkIndex(index, SizeOf.SHORT); 235 return Memory.peekShort(backingArray, arrayOffset + index, order); 236 } 237 238 @Override public final boolean isDirect() { 239 return false; 240 } 241 242 @Override public ByteBuffer put(byte b) { 243 if (isReadOnly) { 244 throw new ReadOnlyBufferException(); 245 } 246 if (position == limit) { 247 throw new BufferOverflowException(); 248 } 249 backingArray[arrayOffset + position++] = b; 250 return this; 251 } 252 253 @Override public ByteBuffer put(int index, byte b) { 254 if (isReadOnly) { 255 throw new ReadOnlyBufferException(); 256 } 257 checkIndex(index); 258 backingArray[arrayOffset + index] = b; 259 return this; 260 } 261 262 @Override public ByteBuffer put(byte[] src, int srcOffset, int byteCount) { 263 if (isReadOnly) { 264 throw new ReadOnlyBufferException(); 265 } 266 checkPutBounds(1, src.length, srcOffset, byteCount); 267 System.arraycopy(src, srcOffset, backingArray, arrayOffset + position, byteCount); 268 position += byteCount; 269 return this; 270 } 271 272 final void put(char[] src, int srcOffset, int charCount) { 273 int byteCount = checkPutBounds(SizeOf.CHAR, src.length, srcOffset, charCount); 274 Memory.unsafeBulkPut(backingArray, arrayOffset + position, byteCount, src, srcOffset, SizeOf.CHAR, order.needsSwap); 275 position += byteCount; 276 } 277 278 final void put(double[] src, int srcOffset, int doubleCount) { 279 int byteCount = checkPutBounds(SizeOf.DOUBLE, src.length, srcOffset, doubleCount); 280 Memory.unsafeBulkPut(backingArray, arrayOffset + position, byteCount, src, srcOffset, SizeOf.DOUBLE, order.needsSwap); 281 position += byteCount; 282 } 283 284 final void put(float[] src, int srcOffset, int floatCount) { 285 int byteCount = checkPutBounds(SizeOf.FLOAT, src.length, srcOffset, floatCount); 286 Memory.unsafeBulkPut(backingArray, arrayOffset + position, byteCount, src, srcOffset, SizeOf.FLOAT, order.needsSwap); 287 position += byteCount; 288 } 289 290 final void put(int[] src, int srcOffset, int intCount) { 291 int byteCount = checkPutBounds(SizeOf.INT, src.length, srcOffset, intCount); 292 Memory.unsafeBulkPut(backingArray, arrayOffset + position, byteCount, src, srcOffset, SizeOf.INT, order.needsSwap); 293 position += byteCount; 294 } 295 296 final void put(long[] src, int srcOffset, int longCount) { 297 int byteCount = checkPutBounds(SizeOf.LONG, src.length, srcOffset, longCount); 298 Memory.unsafeBulkPut(backingArray, arrayOffset + position, byteCount, src, srcOffset, SizeOf.LONG, order.needsSwap); 299 position += byteCount; 300 } 301 302 final void put(short[] src, int srcOffset, int shortCount) { 303 int byteCount = checkPutBounds(SizeOf.SHORT, src.length, srcOffset, shortCount); 304 Memory.unsafeBulkPut(backingArray, arrayOffset + position, byteCount, src, srcOffset, SizeOf.SHORT, order.needsSwap); 305 position += byteCount; 306 } 307 308 @Override public ByteBuffer putChar(int index, char value) { 309 if (isReadOnly) { 310 throw new ReadOnlyBufferException(); 311 } 312 checkIndex(index, SizeOf.CHAR); 313 Memory.pokeShort(backingArray, arrayOffset + index, (short) value, order); 314 return this; 315 } 316 317 @Override public ByteBuffer putChar(char value) { 318 if (isReadOnly) { 319 throw new ReadOnlyBufferException(); 320 } 321 int newPosition = position + SizeOf.CHAR; 322 if (newPosition > limit) { 323 throw new BufferOverflowException(); 324 } 325 Memory.pokeShort(backingArray, arrayOffset + position, (short) value, order); 326 position = newPosition; 327 return this; 328 } 329 330 @Override public ByteBuffer putDouble(double value) { 331 return putLong(Double.doubleToRawLongBits(value)); 332 } 333 334 @Override public ByteBuffer putDouble(int index, double value) { 335 return putLong(index, Double.doubleToRawLongBits(value)); 336 } 337 338 @Override public ByteBuffer putFloat(float value) { 339 return putInt(Float.floatToRawIntBits(value)); 340 } 341 342 @Override public ByteBuffer putFloat(int index, float value) { 343 return putInt(index, Float.floatToRawIntBits(value)); 344 } 345 346 @Override public ByteBuffer putInt(int value) { 347 if (isReadOnly) { 348 throw new ReadOnlyBufferException(); 349 } 350 int newPosition = position + SizeOf.INT; 351 if (newPosition > limit) { 352 throw new BufferOverflowException(); 353 } 354 Memory.pokeInt(backingArray, arrayOffset + position, value, order); 355 position = newPosition; 356 return this; 357 } 358 359 @Override public ByteBuffer putInt(int index, int value) { 360 if (isReadOnly) { 361 throw new ReadOnlyBufferException(); 362 } 363 checkIndex(index, SizeOf.INT); 364 Memory.pokeInt(backingArray, arrayOffset + index, value, order); 365 return this; 366 } 367 368 @Override public ByteBuffer putLong(int index, long value) { 369 if (isReadOnly) { 370 throw new ReadOnlyBufferException(); 371 } 372 checkIndex(index, SizeOf.LONG); 373 Memory.pokeLong(backingArray, arrayOffset + index, value, order); 374 return this; 375 } 376 377 @Override public ByteBuffer putLong(long value) { 378 if (isReadOnly) { 379 throw new ReadOnlyBufferException(); 380 } 381 int newPosition = position + SizeOf.LONG; 382 if (newPosition > limit) { 383 throw new BufferOverflowException(); 384 } 385 Memory.pokeLong(backingArray, arrayOffset + position, value, order); 386 position = newPosition; 387 return this; 388 } 389 390 @Override public ByteBuffer putShort(int index, short value) { 391 if (isReadOnly) { 392 throw new ReadOnlyBufferException(); 393 } 394 checkIndex(index, SizeOf.SHORT); 395 Memory.pokeShort(backingArray, arrayOffset + index, value, order); 396 return this; 397 } 398 399 @Override public ByteBuffer putShort(short value) { 400 if (isReadOnly) { 401 throw new ReadOnlyBufferException(); 402 } 403 int newPosition = position + SizeOf.SHORT; 404 if (newPosition > limit) { 405 throw new BufferOverflowException(); 406 } 407 Memory.pokeShort(backingArray, arrayOffset + position, value, order); 408 position = newPosition; 409 return this; 410 } 411 412 @Override public final CharBuffer asCharBuffer() { 413 return ByteBufferAsCharBuffer.asCharBuffer(this); 414 } 415 416 @Override public final DoubleBuffer asDoubleBuffer() { 417 return ByteBufferAsDoubleBuffer.asDoubleBuffer(this); 418 } 419 420 @Override public final FloatBuffer asFloatBuffer() { 421 return ByteBufferAsFloatBuffer.asFloatBuffer(this); 422 } 423 424 @Override public final IntBuffer asIntBuffer() { 425 return ByteBufferAsIntBuffer.asIntBuffer(this); 426 } 427 428 @Override public final LongBuffer asLongBuffer() { 429 return ByteBufferAsLongBuffer.asLongBuffer(this); 430 } 431 432 @Override public final ShortBuffer asShortBuffer() { 433 return ByteBufferAsShortBuffer.asShortBuffer(this); 434 } 435} 436