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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 import java
.nio
.channels
.FileChannel
.MapMode
;
22 import libcore
.io
.Memory
;
23 import libcore
.io
.SizeOf
;
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
;
30 private final boolean isReadOnly
;
32 protected DirectByteBuffer(MemoryBlock block
, int capacity
, int offset
, boolean isReadOnly
, MapMode mapMode
) {
33 super(block
, capacity
, mapMode
, block
.toLong() + offset
);
35 long baseSize
= block
.getSize();
36 // We're throwing this exception after we passed a bogus value
37 // to the superclass constructor, but it doesn't make any
38 // difference in this case.
39 if (baseSize
>= 0 && (capacity
+ offset
) > baseSize
) {
40 throw new IllegalArgumentException("capacity + offset > baseSize");
44 this.isReadOnly
= isReadOnly
;
47 // Used by the JNI NewDirectByteBuffer function.
48 DirectByteBuffer(long address
, int capacity
) {
49 this(MemoryBlock
.wrapFromJni(address
, capacity
), capacity
, 0, false, null);
52 private static DirectByteBuffer
copy(DirectByteBuffer other
, int markOfOther
, boolean isReadOnly
) {
53 other
.checkNotFreed();
54 DirectByteBuffer buf
= new DirectByteBuffer(other
.block
, other
.capacity(), other
.offset
, isReadOnly
, other
.mapMode
);
55 buf
.limit
= other
.limit
;
56 buf
.position
= other
.position();
57 buf
.mark
= markOfOther
;
61 @Override public ByteBuffer
asReadOnlyBuffer() {
62 return copy(this, mark
, true);
65 @Override public ByteBuffer
compact() {
68 throw new ReadOnlyBufferException();
70 Memory
.memmove(this, 0, this, position
, remaining());
71 position
= limit
- position
;
77 @Override public ByteBuffer
duplicate() {
78 return copy(this, mark
, isReadOnly
);
81 @Override public ByteBuffer
slice() {
83 return new DirectByteBuffer(block
, remaining(), offset
+ position
, isReadOnly
, mapMode
);
86 @Override public boolean isReadOnly() {
90 @Override byte[] protectedArray() {
93 throw new ReadOnlyBufferException();
95 byte[] array
= this.block
.array();
97 throw new UnsupportedOperationException();
102 @Override int protectedArrayOffset() {
103 protectedArray(); // Throw if we don't have an array or are read-only.
107 @Override boolean protectedHasArray() {
108 return !isReadOnly
&& (block
.array() != null);
111 @Override public final ByteBuffer
get(byte[] dst
, int dstOffset
, int byteCount
) {
113 checkGetBounds(1, dst
.length
, dstOffset
, byteCount
);
114 this.block
.peekByteArray(offset
+ position
, dst
, dstOffset
, byteCount
);
115 position
+= byteCount
;
119 final void get(char[] dst
, int dstOffset
, int charCount
) {
121 int byteCount
= checkGetBounds(SizeOf
.CHAR
, dst
.length
, dstOffset
, charCount
);
122 this.block
.peekCharArray(offset
+ position
, dst
, dstOffset
, charCount
, order
.needsSwap
);
123 position
+= byteCount
;
126 final void get(double[] dst
, int dstOffset
, int doubleCount
) {
128 int byteCount
= checkGetBounds(SizeOf
.DOUBLE
, dst
.length
, dstOffset
, doubleCount
);
129 this.block
.peekDoubleArray(offset
+ position
, dst
, dstOffset
, doubleCount
, order
.needsSwap
);
130 position
+= byteCount
;
133 final void get(float[] dst
, int dstOffset
, int floatCount
) {
135 int byteCount
= checkGetBounds(SizeOf
.FLOAT
, dst
.length
, dstOffset
, floatCount
);
136 this.block
.peekFloatArray(offset
+ position
, dst
, dstOffset
, floatCount
, order
.needsSwap
);
137 position
+= byteCount
;
140 final void get(int[] dst
, int dstOffset
, int intCount
) {
142 int byteCount
= checkGetBounds(SizeOf
.INT
, dst
.length
, dstOffset
, intCount
);
143 this.block
.peekIntArray(offset
+ position
, dst
, dstOffset
, intCount
, order
.needsSwap
);
144 position
+= byteCount
;
147 final void get(long[] dst
, int dstOffset
, int longCount
) {
149 int byteCount
= checkGetBounds(SizeOf
.LONG
, dst
.length
, dstOffset
, longCount
);
150 this.block
.peekLongArray(offset
+ position
, dst
, dstOffset
, longCount
, order
.needsSwap
);
151 position
+= byteCount
;
154 final void get(short[] dst
, int dstOffset
, int shortCount
) {
156 int byteCount
= checkGetBounds(SizeOf
.SHORT
, dst
.length
, dstOffset
, shortCount
);
157 this.block
.peekShortArray(offset
+ position
, dst
, dstOffset
, shortCount
, order
.needsSwap
);
158 position
+= byteCount
;
161 @Override public final byte get() {
163 if (position
== limit
) {
164 throw new BufferUnderflowException();
166 return this.block
.peekByte(offset
+ position
++);
169 @Override public final byte get(int index
) {
172 return this.block
.peekByte(offset
+ index
);
175 @Override public final char getChar() {
177 int newPosition
= position
+ SizeOf
.CHAR
;
178 if (newPosition
> limit
) {
179 throw new BufferUnderflowException();
181 char result
= (char) this.block
.peekShort(offset
+ position
, order
);
182 position
= newPosition
;
186 @Override public final char getChar(int index
) {
188 checkIndex(index
, SizeOf
.CHAR
);
189 return (char) this.block
.peekShort(offset
+ index
, order
);
192 @Override public final double getDouble() {
194 int newPosition
= position
+ SizeOf
.DOUBLE
;
195 if (newPosition
> limit
) {
196 throw new BufferUnderflowException();
198 double result
= Double
.longBitsToDouble(this.block
.peekLong(offset
+ position
, order
));
199 position
= newPosition
;
203 @Override public final double getDouble(int index
) {
205 checkIndex(index
, SizeOf
.DOUBLE
);
206 return Double
.longBitsToDouble(this.block
.peekLong(offset
+ index
, order
));
209 @Override public final float getFloat() {
211 int newPosition
= position
+ SizeOf
.FLOAT
;
212 if (newPosition
> limit
) {
213 throw new BufferUnderflowException();
215 float result
= Float
.intBitsToFloat(this.block
.peekInt(offset
+ position
, order
));
216 position
= newPosition
;
220 @Override public final float getFloat(int index
) {
222 checkIndex(index
, SizeOf
.FLOAT
);
223 return Float
.intBitsToFloat(this.block
.peekInt(offset
+ index
, order
));
226 @Override public final int getInt() {
228 int newPosition
= position
+ SizeOf
.INT
;
229 if (newPosition
> limit
) {
230 throw new BufferUnderflowException();
232 int result
= this.block
.peekInt(offset
+ position
, order
);
233 position
= newPosition
;
237 @Override public final int getInt(int index
) {
239 checkIndex(index
, SizeOf
.INT
);
240 return this.block
.peekInt(offset
+ index
, order
);
243 @Override public final long getLong() {
245 int newPosition
= position
+ SizeOf
.LONG
;
246 if (newPosition
> limit
) {
247 throw new BufferUnderflowException();
249 long result
= this.block
.peekLong(offset
+ position
, order
);
250 position
= newPosition
;
254 @Override public final long getLong(int index
) {
256 checkIndex(index
, SizeOf
.LONG
);
257 return this.block
.peekLong(offset
+ index
, order
);
260 @Override public final short getShort() {
262 int newPosition
= position
+ SizeOf
.SHORT
;
263 if (newPosition
> limit
) {
264 throw new BufferUnderflowException();
266 short result
= this.block
.peekShort(offset
+ position
, order
);
267 position
= newPosition
;
271 @Override public final short getShort(int index
) {
273 checkIndex(index
, SizeOf
.SHORT
);
274 return this.block
.peekShort(offset
+ index
, order
);
277 @Override public final boolean isDirect() {
282 @Override public final boolean isAccessible() {
283 return block
.isAccessible();
287 @Override public void setAccessible(boolean accessible
) {
288 block
.setAccessible(accessible
);
292 * Invalidates the buffer. Subsequent operations which touch the inner
293 * buffer will throw {@link IllegalStateException}.
295 public final void free() {
299 @Override public final CharBuffer
asCharBuffer() {
301 return ByteBufferAsCharBuffer
.asCharBuffer(this);
304 @Override public final DoubleBuffer
asDoubleBuffer() {
306 return ByteBufferAsDoubleBuffer
.asDoubleBuffer(this);
309 @Override public final FloatBuffer
asFloatBuffer() {
311 return ByteBufferAsFloatBuffer
.asFloatBuffer(this);
314 @Override public final IntBuffer
asIntBuffer() {
316 return ByteBufferAsIntBuffer
.asIntBuffer(this);
319 @Override public final LongBuffer
asLongBuffer() {
321 return ByteBufferAsLongBuffer
.asLongBuffer(this);
324 @Override public final ShortBuffer
asShortBuffer() {
326 return ByteBufferAsShortBuffer
.asShortBuffer(this);
329 @Override public ByteBuffer
put(byte value
) {
332 throw new ReadOnlyBufferException();
334 if (position
== limit
) {
335 throw new BufferOverflowException();
337 this.block
.pokeByte(offset
+ position
++, value
);
341 @Override public ByteBuffer
put(int index
, byte value
) {
344 throw new ReadOnlyBufferException();
347 this.block
.pokeByte(offset
+ index
, value
);
351 @Override public ByteBuffer
put(byte[] src
, int srcOffset
, int byteCount
) {
354 throw new ReadOnlyBufferException();
356 checkPutBounds(1, src
.length
, srcOffset
, byteCount
);
357 this.block
.pokeByteArray(offset
+ position
, src
, srcOffset
, byteCount
);
358 position
+= byteCount
;
362 final void put(char[] src
, int srcOffset
, int charCount
) {
364 int byteCount
= checkPutBounds(SizeOf
.CHAR
, src
.length
, srcOffset
, charCount
);
365 this.block
.pokeCharArray(offset
+ position
, src
, srcOffset
, charCount
, order
.needsSwap
);
366 position
+= byteCount
;
369 final void put(double[] src
, int srcOffset
, int doubleCount
) {
371 int byteCount
= checkPutBounds(SizeOf
.DOUBLE
, src
.length
, srcOffset
, doubleCount
);
372 this.block
.pokeDoubleArray(offset
+ position
, src
, srcOffset
, doubleCount
, order
.needsSwap
);
373 position
+= byteCount
;
376 final void put(float[] src
, int srcOffset
, int floatCount
) {
378 int byteCount
= checkPutBounds(SizeOf
.FLOAT
, src
.length
, srcOffset
, floatCount
);
379 this.block
.pokeFloatArray(offset
+ position
, src
, srcOffset
, floatCount
, order
.needsSwap
);
380 position
+= byteCount
;
383 final void put(int[] src
, int srcOffset
, int intCount
) {
385 int byteCount
= checkPutBounds(SizeOf
.INT
, src
.length
, srcOffset
, intCount
);
386 this.block
.pokeIntArray(offset
+ position
, src
, srcOffset
, intCount
, order
.needsSwap
);
387 position
+= byteCount
;
390 final void put(long[] src
, int srcOffset
, int longCount
) {
392 int byteCount
= checkPutBounds(SizeOf
.LONG
, src
.length
, srcOffset
, longCount
);
393 this.block
.pokeLongArray(offset
+ position
, src
, srcOffset
, longCount
, order
.needsSwap
);
394 position
+= byteCount
;
397 final void put(short[] src
, int srcOffset
, int shortCount
) {
399 int byteCount
= checkPutBounds(SizeOf
.SHORT
, src
.length
, srcOffset
, shortCount
);
400 this.block
.pokeShortArray(offset
+ position
, src
, srcOffset
, shortCount
, order
.needsSwap
);
401 position
+= byteCount
;
404 @Override public ByteBuffer
putChar(char value
) {
407 throw new ReadOnlyBufferException();
409 int newPosition
= position
+ SizeOf
.CHAR
;
410 if (newPosition
> limit
) {
411 throw new BufferOverflowException();
413 this.block
.pokeShort(offset
+ position
, (short) value
, order
);
414 position
= newPosition
;
418 @Override public ByteBuffer
putChar(int index
, char value
) {
421 throw new ReadOnlyBufferException();
423 checkIndex(index
, SizeOf
.CHAR
);
424 this.block
.pokeShort(offset
+ index
, (short) value
, order
);
428 @Override public ByteBuffer
putDouble(double value
) {
431 throw new ReadOnlyBufferException();
433 int newPosition
= position
+ SizeOf
.DOUBLE
;
434 if (newPosition
> limit
) {
435 throw new BufferOverflowException();
437 this.block
.pokeLong(offset
+ position
, Double
.doubleToRawLongBits(value
), order
);
438 position
= newPosition
;
442 @Override public ByteBuffer
putDouble(int index
, double value
) {
445 throw new ReadOnlyBufferException();
447 checkIndex(index
, SizeOf
.DOUBLE
);
448 this.block
.pokeLong(offset
+ index
, Double
.doubleToRawLongBits(value
), order
);
452 @Override public ByteBuffer
putFloat(float value
) {
455 throw new ReadOnlyBufferException();
457 int newPosition
= position
+ SizeOf
.FLOAT
;
458 if (newPosition
> limit
) {
459 throw new BufferOverflowException();
461 this.block
.pokeInt(offset
+ position
, Float
.floatToRawIntBits(value
), order
);
462 position
= newPosition
;
466 @Override public ByteBuffer
putFloat(int index
, float value
) {
469 throw new ReadOnlyBufferException();
471 checkIndex(index
, SizeOf
.FLOAT
);
472 this.block
.pokeInt(offset
+ index
, Float
.floatToRawIntBits(value
), order
);
476 @Override public ByteBuffer
putInt(int value
) {
479 throw new ReadOnlyBufferException();
481 int newPosition
= position
+ SizeOf
.INT
;
482 if (newPosition
> limit
) {
483 throw new BufferOverflowException();
485 this.block
.pokeInt(offset
+ position
, value
, order
);
486 position
= newPosition
;
490 @Override public ByteBuffer
putInt(int index
, int value
) {
493 throw new ReadOnlyBufferException();
495 checkIndex(index
, SizeOf
.INT
);
496 this.block
.pokeInt(offset
+ index
, value
, order
);
500 @Override public ByteBuffer
putLong(long value
) {
503 throw new ReadOnlyBufferException();
505 int newPosition
= position
+ SizeOf
.LONG
;
506 if (newPosition
> limit
) {
507 throw new BufferOverflowException();
509 this.block
.pokeLong(offset
+ position
, value
, order
);
510 position
= newPosition
;
514 @Override public ByteBuffer
putLong(int index
, long value
) {
517 throw new ReadOnlyBufferException();
519 checkIndex(index
, SizeOf
.LONG
);
520 this.block
.pokeLong(offset
+ index
, value
, order
);
524 @Override public ByteBuffer
putShort(short value
) {
527 throw new ReadOnlyBufferException();
529 int newPosition
= position
+ SizeOf
.SHORT
;
530 if (newPosition
> limit
) {
531 throw new BufferOverflowException();
533 this.block
.pokeShort(offset
+ position
, value
, order
);
534 position
= newPosition
;
538 @Override public ByteBuffer
putShort(int index
, short value
) {
541 throw new ReadOnlyBufferException();
543 checkIndex(index
, SizeOf
.SHORT
);
544 this.block
.pokeShort(offset
+ index
, value
, order
);
548 private void checkIsAccessible() {
550 if (!block
.isAccessible()) {
551 throw new IllegalStateException("buffer is inaccessible");
555 private void checkNotFreed() {
556 if (block
.isFreed()) {
557 throw new IllegalStateException("buffer was freed");