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