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 libcore.io.SizeOf;
     21 import libcore.io.Memory;
     22 
     23 /**
     24  * ByteArrayBuffer implements byte[]-backed ByteBuffers.
     25  */
     26 final 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